You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by th...@apache.org on 2014/12/06 23:30:12 UTC
[01/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Repository: tapestry-5
Updated Branches:
refs/heads/beanmodel-split [created] 696bc7ae8
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
deleted file mode 100644
index 2feaeca..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2008-2013 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.ioc.util;
-
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAccess;
-
-/**
- * Contains static methods useful for manipulating exceptions.
- */
-public class ExceptionUtils
-{
- /**
- * Locates a particular type of exception, working its way via the cause property of each exception in the exception
- * stack.
- *
- * @param t the outermost exception
- * @param type the type of exception to search for
- * @return the first exception of the given type, if found, or null
- */
- public static <T extends Throwable> T findCause(Throwable t, Class<T> type)
- {
- Throwable current = t;
-
- while (current != null)
- {
- if (type.isInstance(current))
- {
- return type.cast(current);
- }
-
- // Not a match, work down.
-
- current = current.getCause();
- }
-
- return null;
- }
-
- /**
- * Locates a particular type of exception, working its way down via any property that returns some type of Exception.
- * This is more expensive, but more accurate, than {@link #findCause(Throwable, Class)} as it works with older exceptions
- * that do not properly implement the (relatively new) {@linkplain Throwable#getCause() cause property}.
- *
- * @param t the outermost exception
- * @param type the type of exception to search for
- * @param access used to access properties
- * @return the first exception of the given type, if found, or null
- */
- public static <T extends Throwable> T findCause(Throwable t, Class<T> type, PropertyAccess access)
- {
- Throwable current = t;
-
- while (current != null)
- {
- if (type.isInstance(current))
- {
- return type.cast(current);
- }
-
- Throwable next = null;
-
- ClassPropertyAdapter adapter = access.getAdapter(current);
-
- for (String name : adapter.getPropertyNames())
- {
-
- Object value = adapter.getPropertyAdapter(name).get(current);
-
- if (value != null && value != current && value instanceof Throwable)
- {
- next = (Throwable) value;
- break;
- }
- }
-
- current = next;
- }
-
-
- return null;
- }
-
- /**
- * Extracts the message from an exception. If the exception's message is null, returns the exceptions class name.
- *
- * @param exception
- * to extract message from
- * @return message or class name
- * @since 5.4
- */
- public static String toMessage(Throwable exception)
- {
- assert exception != null;
-
- String message = exception.getMessage();
-
- if (message != null)
- return message;
-
- return exception.getClass().getName();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
deleted file mode 100644
index 470b611..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.ioc.util;
-
-import org.apache.tapestry5.ioc.internal.util.TapestryException;
-
-/**
- * Special exception used when a value (typically from a map) is referenced that does not exist. Uses a
- * {@link AvailableValues} object
- * to track what the known values are.
- *
- * @since 5.2.0
- */
-public class UnknownValueException extends TapestryException
-{
- private final AvailableValues availableValues;
-
- public UnknownValueException(String message, AvailableValues availableValues)
- {
- this(message, null, null, availableValues);
- }
-
- public UnknownValueException(String message, Object location, Throwable cause, AvailableValues availableValues)
- {
- super(message, location, cause);
-
- this.availableValues = availableValues;
- }
-
- public AvailableValues getAvailableValues()
- {
- return availableValues;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry5-annotations/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/build.gradle b/tapestry5-annotations/build.gradle
index 7d7657c..4f411a1 100644
--- a/tapestry5-annotations/build.gradle
+++ b/tapestry5-annotations/build.gradle
@@ -1 +1 @@
-description = "Annotations used with Tapestry applications"
\ No newline at end of file
+description = "Annotations used with Tapestry, Tapestry-IoC and BeanModel applications"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
new file mode 100644
index 0000000..2e03557
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
@@ -0,0 +1,34 @@
+// Copyright 2008, 2009 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.ioc.annotations;
+
+import java.lang.annotation.*;
+
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have an {@linkplain
+ * org.apache.tapestry5.ioc.Configuration unordered configuration}, to identify the type of contribution.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesConfiguration
+{
+ /**
+ * The type of object which may be contributed into the service's configuration.
+ */
+ Class value();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentClasses.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
new file mode 100644
index 0000000..c901d3a
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
@@ -0,0 +1,35 @@
+// Copyright 2008, 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.services;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marker annotation used to inject the correct {@link org.apache.tapestry5.services.InvalidationEventHub} service
+ * responsible for invalidations when underlying component class files are changed.
+ *
+ * @since 5.1.0.0
+ */
+@Target(
+{ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ComponentClasses
+{
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentLayer.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
new file mode 100644
index 0000000..e342c3f
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
@@ -0,0 +1,37 @@
+// 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.services;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Marker annotation used to identify a service from the component layer that conflicts, in terms of service interface,
+ * with a service from elsewhere. In particular, this is used to disambiguate {@link org.apache.tapestry5.ioc.services.PlasticProxyFactory} which has one implementation (marked with {@link
+ * org.apache.tapestry5.ioc.services.Builtin} and another with this annotation.
+ */
+@Target(
+ {PARAMETER, FIELD})
+@Retention(RUNTIME)
+@Documented
+public @interface ComponentLayer
+{
+
+}
[08/15] tapestry-5 git commit: Second pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
Second pass creating the BeanModel and Commons packages.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/1f36bb20
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/1f36bb20
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/1f36bb20
Branch: refs/heads/beanmodel-split
Commit: 1f36bb203cb0646f912125caa3bd03707aa95083
Parents: f963c7a
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 16:40:55 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 16:40:55 2014 -0200
----------------------------------------------------------------------
.../internal/antlr/PropertyExpressionLexer.g | 163 +++++++++++++++++
.../internal/antlr/PropertyExpressionParser.g | 105 +++++++++++
.../tapestry5/internal/antlr/BaseLexer.java | 54 ++++++
.../tapestry5/internal/antlr/BaseParser.java | 40 +++++
.../tapestry5/internal/antlr/package-info.java | 18 ++
.../tapestry5/internal/services/Invariant.java | 28 +++
.../services/LiteralPropertyConduit.java | 85 +++++++++
.../services/PropertyExpressionException.java | 38 ++++
.../internal/services/StringInterner.java | 43 +++++
.../org/apache/tapestry5/ioc/ObjectCreator.java | 27 +++
.../ioc/services/PlasticProxyFactory.java | 159 +++++++++++++++++
.../org/apache/tapestry5/ioc/util/Stack.java | 173 +++++++++++++++++++
.../internal/antlr/PropertyExpressionLexer.g | 163 -----------------
.../internal/antlr/PropertyExpressionParser.g | 105 -----------
.../tapestry5/internal/antlr/BaseLexer.java | 54 ------
.../tapestry5/internal/antlr/BaseParser.java | 40 -----
.../tapestry5/internal/antlr/package-info.java | 18 --
.../tapestry5/internal/services/Invariant.java | 28 ---
.../services/LiteralPropertyConduit.java | 85 ---------
.../services/PropertyExpressionException.java | 38 ----
.../internal/services/StringInterner.java | 43 -----
.../org/apache/tapestry5/ioc/ObjectCreator.java | 27 ---
.../ioc/annotations/IncompatibleChange.java | 33 ----
.../ioc/services/PlasticProxyFactory.java | 159 -----------------
.../org/apache/tapestry5/ioc/util/Stack.java | 173 -------------------
.../ioc/annotations/IncompatibleChange.java | 33 ++++
26 files changed, 966 insertions(+), 966 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
new file mode 100644
index 0000000..3b52ba9
--- /dev/null
+++ b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
@@ -0,0 +1,163 @@
+// Copyright 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.
+
+lexer grammar PropertyExpressionLexer;
+
+
+options
+{
+ superClass='org.apache.tapestry5.internal.antlr.BaseLexer';
+}
+
+@header
+{
+package org.apache.tapestry5.internal.antlr;
+}
+
+
+// Integer constant
+fragment INTEGER
+ : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
+
+// Read a property or invoke a method.
+fragment DEREF
+ : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
+
+// Range operator, ".." between two integers.
+fragment RANGEOP
+ : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
+
+// Decimal number
+fragment DECIMAL
+ : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
+
+fragment LETTER
+ : ('a'..'z'|'A'..'Z');
+fragment DIGIT
+ : '0'..'9';
+fragment SIGN
+ : ('+'|'-');
+LPAREN : '(';
+RPAREN : ')';
+LBRACKET: '[';
+RBRACKET: ']';
+COMMA : ',';
+BANG : '!';
+LBRACE : '{';
+RBRACE : '}';
+COLON : ':';
+
+fragment QUOTE
+ : '\'';
+
+// Clumsy but effective approach to case-insensitive identifiers.
+
+fragment A
+ : ('a' | 'A');
+fragment E
+ : ('e' | 'E');
+fragment F
+ : ('f' | 'F');
+fragment H
+ : ('h' | 'H');
+fragment I
+ : ('i' | 'I');
+fragment L
+ : ('l' | 'L');
+fragment N
+ : ('n'|'N');
+fragment R
+ : ('r' | 'R');
+fragment S
+ : ('s' | 'S');
+fragment T
+ : ('t' | 'T');
+fragment U
+ : ('u' | 'U');
+
+// Identifiers are case insensitive
+
+NULL : N U L L;
+TRUE : T R U E;
+FALSE : F A L S E;
+THIS : T H I S;
+
+IDENTIFIER
+ : JAVA_ID_START (JAVA_ID_PART)*
+ ;
+
+fragment
+JAVA_ID_START
+ : '\u0024'
+ | '\u0041'..'\u005a'
+ | '\u005f'
+ | '\u0061'..'\u007a'
+ | '\u00c0'..'\u00d6'
+ | '\u00d8'..'\u00f6'
+ | '\u00f8'..'\u00ff'
+ | '\u0100'..'\u1fff'
+ | '\u3040'..'\u318f'
+ | '\u3300'..'\u337f'
+ | '\u3400'..'\u3d2d'
+ | '\u4e00'..'\u9fff'
+ | '\uf900'..'\ufaff'
+ ;
+
+fragment
+JAVA_ID_PART
+ : JAVA_ID_START
+ | '\u0030'..'\u0039'
+ ;
+
+
+// The Safe Dereference operator understands not to de-reference through
+// a null.
+
+SAFEDEREF
+ : '?.';
+
+WS : (' '|'\t'|'\n'|'\r')+ { skip(); };
+
+
+// Literal strings are always inside single quotes.
+STRING
+ : QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); };
+
+
+// Special rule that uses parsing tricks to identify numbers and ranges; it's all about
+// the dot ('.').
+// Recognizes:
+// '.' as DEREF
+// '..' as RANGEOP
+// INTEGER (sign? digit+)
+// DECIMAL (sign? digits* . digits+)
+// Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10").
+
+NUMBER_OR_RANGEOP
+ : SIGN? DIGIT+
+ (
+ { input.LA(2) != '.' }? => '.' DIGIT* { $type = DECIMAL; stripLeadingPlus(); }
+ | { $type = INTEGER; stripLeadingPlus(); }
+ )
+
+ | SIGN '.' DIGIT+ { $type = DECIMAL; stripLeadingPlus(); }
+
+ | '.'
+ (
+ DIGIT+ { $type = DECIMAL; stripLeadingPlus();}
+ | '.' {$type = RANGEOP; }
+ | {$type = DEREF; }
+ )
+ ;
+
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
new file mode 100644
index 0000000..14753e6
--- /dev/null
+++ b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
@@ -0,0 +1,105 @@
+// Copyright 2008, 2009, 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.
+
+parser grammar PropertyExpressionParser;
+
+
+options
+{
+ superClass='org.apache.tapestry5.internal.antlr.BaseParser';
+ output=AST;
+ ASTLabelType=CommonTree;
+ tokenVocab=PropertyExpressionLexer;
+ backtrack=true;
+}
+
+tokens
+{
+ // Parser token representing a method invocation
+ INVOKE;
+ // A List (top level, or as method parameter)
+ LIST;
+ //A Map (top level, or as method parameter)
+ MAP;
+ // Not operation (invert a boolean)
+ NOT;
+}
+
+@header
+{
+package org.apache.tapestry5.internal.antlr;
+}
+
+
+start : expression^ EOF!;
+
+expression
+ : keyword
+ | rangeOp
+ | constant
+ | propertyChain
+ | list
+ | notOp
+ | map
+ ;
+
+keyword : NULL | TRUE | FALSE | THIS;
+
+constant: INTEGER| DECIMAL | STRING;
+
+propertyChain
+ : term DEREF propertyChain -> ^(DEREF term propertyChain)
+ | term SAFEDEREF propertyChain -> ^(SAFEDEREF term propertyChain)
+ | term
+ ;
+
+term : IDENTIFIER
+ | methodInvocation
+ ;
+
+methodInvocation
+ : id=IDENTIFIER LPAREN RPAREN -> ^(INVOKE $id)
+ | id=IDENTIFIER LPAREN expressionList RPAREN -> ^(INVOKE $id expressionList)
+ ;
+
+expressionList
+ : expression (COMMA! expression)*
+ ;
+
+rangeOp
+ : from=rangeopArg RANGEOP to=rangeopArg -> ^(RANGEOP $from $to)
+ ;
+
+rangeopArg
+ : INTEGER
+ | propertyChain
+ ;
+
+list : LBRACKET RBRACKET -> ^(LIST)
+ | LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
+ ;
+
+notOp : BANG expression -> ^(NOT expression)
+ ;
+
+map : LBRACE RBRACE -> ^(MAP)
+ | LBRACE mapEntryList RBRACE -> ^(MAP mapEntryList)
+ ;
+
+mapEntryList : mapEntry (COMMA! mapEntry)*;
+
+mapEntry : mapKey COLON! expression;
+
+mapKey : keyword | constant | propertyChain;
+
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
new file mode 100644
index 0000000..442240d
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
@@ -0,0 +1,54 @@
+// Copyright 2008, 2009 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.antlr;
+
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.Lexer;
+import org.antlr.runtime.RecognizerSharedState;
+import org.antlr.runtime.RecognitionException;
+
+public abstract class BaseLexer extends Lexer
+{
+ protected BaseLexer()
+ {
+ }
+
+ protected BaseLexer(CharStream charStream,
+ RecognizerSharedState recognizerSharedState)
+ {
+ super(charStream, recognizerSharedState);
+ }
+
+ protected void stripLeadingPlus()
+ {
+ String text = getText();
+
+ // For compatibility with Tapestry 5.0, we need to allow a sign of '+', which Long.parseLong()
+ // doesn't accept. To keep things downstream simple, we eliminate the '+' here.
+
+ if (text.startsWith("+"))
+ {
+ setText(text.substring(1));
+ }
+ }
+
+ @Override
+ public void reportError(RecognitionException e)
+ {
+ throw new RuntimeException(String.format("Unable to parse input at character position %d",
+ e.charPositionInLine + 1),
+ e);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
new file mode 100644
index 0000000..212b782
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
@@ -0,0 +1,40 @@
+// Copyright 2009 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.antlr;
+
+import org.antlr.runtime.Parser;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.RecognizerSharedState;
+
+public class BaseParser extends Parser
+{
+ public BaseParser(TokenStream tokenStream)
+ {
+ super(tokenStream);
+ }
+
+ public BaseParser(TokenStream tokenStream,
+ RecognizerSharedState recognizerSharedState)
+ {
+ super(tokenStream, recognizerSharedState);
+ }
+
+ @Override
+ public void emitErrorMessage(String message)
+ {
+ // This is caught and more properly reported later.
+ throw new RuntimeException(message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
new file mode 100644
index 0000000..55be313
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
@@ -0,0 +1,18 @@
+// Copyright 2012 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.
+
+/**
+ * [INTERNAL USE ONLY] support classes related to Antlr; API subject to change
+ */
+package org.apache.tapestry5.internal.antlr;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
new file mode 100644
index 0000000..924b570
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
@@ -0,0 +1,28 @@
+// Copyright 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.internal.services;
+
+import java.lang.annotation.*;
+
+/**
+ * Special annotation that is applied to literal {@link org.apache.tapestry5.PropertyConduit}s, to inform {@link
+ * org.apache.tapestry5.internal.bindings.PropBinding} that the value is, in fact, invariant.
+ */
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Invariant
+{
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
new file mode 100644
index 0000000..1fffd4f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
@@ -0,0 +1,85 @@
+// Copyright 2008, 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 java.lang.reflect.Type;
+
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+/**
+ * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
+ */
+public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
+{
+ private final Class propertyType;
+
+ private final AnnotationProvider annotationProvider;
+
+ private final String description;
+
+ private final Object value;
+
+ public LiteralPropertyConduit(TypeCoercer typeCoercer, Class propertyType, AnnotationProvider annotationProvider,
+ String description, Object value)
+ {
+ super(typeCoercer);
+
+ this.propertyType = propertyType;
+ this.annotationProvider = annotationProvider;
+ this.description = description;
+
+ this.value = value;
+ }
+
+ public Object get(Object instance)
+ {
+ return value;
+ }
+
+ public void set(Object instance, Object value)
+ {
+ throw new RuntimeException("Literal values are not updateable.");
+ }
+
+ public Class getPropertyType()
+ {
+ return propertyType;
+ }
+
+ public Type getPropertyGenericType()
+ {
+ return propertyType;
+ }
+
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationProvider.getAnnotation(annotationClass);
+ }
+
+ public String getPropertyName()
+ {
+ return null;
+ }
+
+ @Override
+ public String toString()
+ {
+ return description;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
new file mode 100644
index 0000000..765c0bb
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
@@ -0,0 +1,38 @@
+// Copyright 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.internal.services;
+
+/**
+ * Exception thrown when there is a problem parsing a property expression using the ANTLR property expression grammar.
+ */
+public class PropertyExpressionException extends RuntimeException
+{
+ private final String expression;
+
+ public PropertyExpressionException(String message, String expression, Throwable cause)
+ {
+ super(message, cause);
+
+ this.expression = expression;
+ }
+
+ /**
+ * Returns the property expression containing the error.
+ */
+ public String getExpression()
+ {
+ return expression;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
new file mode 100644
index 0000000..78ee5f4
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
@@ -0,0 +1,43 @@
+// Copyright 2009 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;
+
+/**
+ * Creates "interned" strings that are unique for the same content. This is used for common description strings,
+ * particularly those used by {@link org.apache.tapestry5.Binding} instances. The internal cache of interned strings id
+ * cleared whenever the {@link org.apache.tapestry5.services.ComponentClasses} {@link
+ * org.apache.tapestry5.services.InvalidationEventHub} is invalidated (i.e., when component class files change).
+ *
+ * @since 5.1.0.0
+ */
+public interface StringInterner
+{
+ /**
+ * Interns a string.
+ *
+ * @param string the string to intern
+ * @return the input string, or another string instance with the same content
+ */
+ String intern(String string);
+
+ /**
+ * Formats a string (using {@link String#format(String, Object[])}) and returns the interned result.
+ *
+ * @param format string format
+ * @param arguments used inside the format
+ * @return formatted and interned string
+ */
+ String format(String format, Object... arguments);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
new file mode 100644
index 0000000..e7990fc
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
@@ -0,0 +1,27 @@
+// Copyright 2006, 2008, 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.ioc;
+
+/**
+ * Interface used to encapsulate any strategy used defer the creation of some object until just as needed.
+ */
+public interface ObjectCreator<T>
+{
+ /**
+ * Create and return the object. In some limited circumstances, the implementation may cache the result, returning
+ * the same object for repeated calls.
+ */
+ T createObject();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
new file mode 100644
index 0000000..75e93e4
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
@@ -0,0 +1,159 @@
+// Copyright 2011, 2012 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.ioc.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
+import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.PlasticClassListenerHub;
+import org.apache.tapestry5.plastic.PlasticClassTransformation;
+import org.apache.tapestry5.plastic.PlasticClassTransformer;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * A service used to create proxies of varying types. As a secondary concern, manages to identify the
+ * location of methods and constructors, which is important for exception reporting.
+ *
+ * @since 5.3
+ */
+public interface PlasticProxyFactory extends PlasticClassListenerHub
+{
+ /**
+ * Returns the class loader used when creating new classes, this is a child class loader
+ * of another class loader (usually, the thread's context class loader).
+ */
+ ClassLoader getClassLoader();
+
+ /**
+ * Creates a proxy object that implements the indicated interface, then invokes the callback to further
+ * configure the proxy.
+ *
+ * @param interfaceType
+ * interface implemented by proxy
+ * @param callback
+ * configures the proxy
+ * @return instantiator that can be used to create an instance of the proxy class
+ */
+ <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
+
+ /**
+ * Creates a proxy object that implements the indicated interface and indicated service implementation type,
+ * then invokes the callback to further configure the proxy.
+ *
+ * @param interfaceType
+ * interface implemented by proxy
+ * @param implementationType
+ * a class that implements the interfaceType. It can be null.
+ * @param callback
+ * configures the proxy
+ * @return instantiator that can be used to create an instance of the proxy class
+ */
+ @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+ <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
+
+ /**
+ * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
+ * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+ * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+ *
+ * @param interfaceType
+ * class proxy will extend from
+ * @return transformation from which an instantiator may be created
+ */
+ <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
+
+ /**
+ * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
+ * implementation class. This should only be
+ * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+ * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+ *
+ * @param interfaceType
+ * class proxy will extend from
+ * @param implementationType
+ * a class that implements the interfaceType. It can be null.
+ * @return transformation from which an instantiator may be created
+ */
+ @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+ <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
+
+ /**
+ * Creates a proxy instance that delegates all methods through a corresponding
+ * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+ * creator implementation may decide to
+ * cache the return value as appropriate).
+ *
+ * @param <T>
+ * type of proxy
+ * @param interfaceType
+ * interface class for proxy
+ * @param creator
+ * object responsible for creating the real object
+ * @param description
+ * the <code>toString()</code> of the proxy
+ * @return proxy instance
+ */
+ <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
+
+ /**
+ * Creates a proxy instance that delegates all methods through a corresponding
+ * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+ * creator implementation may decide to
+ * cache the return value as appropriate).
+ *
+ * @param <T>
+ * type of proxy
+ * @param interfaceType
+ * interface class for proxy
+ * @param implementationType
+ * class that implements the interface type. It may be null
+ * @param creator
+ * object responsible for creating the real object
+ * @param description
+ * the <code>toString()</code> of the proxy
+ * @return proxy instance
+ */
+ @IncompatibleChange(release = "5.4", details = "Added for TAP5-2029")
+ <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
+
+ /**
+ * Converts a method to a {@link Location}, which includes information about the source file name and line number.
+ *
+ * @param method
+ * to look up
+ * @return the location (identifying the method and possibly, the line number within the method)
+ */
+ Location getMethodLocation(Method method);
+
+ /**
+ * Return a string representation for the constructor (including class and parameters) and (if available) file name
+ * and line number.
+ *
+ * @return the location (identifying the constructor and possibly, the line number within the method)
+ */
+ Location getConstructorLocation(Constructor constructor);
+
+ /**
+ * Clears any cached information stored by the proxy factory; this is useful in Tapestry development mode
+ * when a class loader may have been discarded (because the proxy factory may indirectly keep references
+ * to classes loaded by the old class loader).
+ *
+ * @since 5.3.3
+ */
+ void clearCache();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
new file mode 100644
index 0000000..cfa13a0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
@@ -0,0 +1,173 @@
+// Copyright 2007, 2008, 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.ioc.util;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+
+/**
+ * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe.
+ *
+ * @param <E> the type of elements stored in the map
+ * @see CollectionFactory#newStack()
+ */
+public class Stack<E>
+{
+ private static final int MINIMUM_SIZE = 3;
+
+ private static final int DEFAULT_ARRAY_SIZE = 20;
+
+ private Object[] items;
+
+ private int index = -1;
+
+ /**
+ * Normal constructor supporting an initial size of 20.
+ */
+ public Stack()
+ {
+ this(DEFAULT_ARRAY_SIZE);
+ }
+
+ /**
+ * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best
+ * efficiency, set this to the maximum depth of the stack.
+ */
+ public Stack(int initialSize)
+ {
+ items = new Object[Math.max(initialSize, MINIMUM_SIZE)];
+ }
+
+ /**
+ * Returns true if the stack is empty.
+ */
+ public boolean isEmpty()
+ {
+ return index < 0;
+ }
+
+ /**
+ * Returns the number of items currently in the stack.
+ */
+ public int getDepth()
+ {
+ return index + 1;
+ }
+
+ /**
+ * Clears the stack, the same as popping off all elements.
+ */
+ public void clear()
+ {
+ for (int i = 0; i <= index; i++) items[i] = null;
+
+ index = -1;
+ }
+
+ /**
+ * Pushes a new item onto the stack.
+ */
+ public void push(E item)
+ {
+ index++;
+
+ if (index == items.length)
+ {
+ int newCapacity = (items.length * 3) / 2 + 1;
+ Object[] newItems = new Object[newCapacity];
+ System.arraycopy(items, 0, newItems, 0, items.length);
+
+ items = newItems;
+ }
+
+ items[index] = item;
+ }
+
+ /**
+ * Pops the top element off the stack and returns it.
+ *
+ * @return the top element of the stack
+ * @throws IllegalStateException if the stack is empty
+ */
+ @SuppressWarnings("unchecked")
+ public E pop()
+ {
+ checkIfEmpty();
+
+ Object result = items[index];
+
+ items[index] = null;
+
+ index--;
+
+ return (E) result;
+ }
+
+ private void checkIfEmpty()
+ {
+ if (index < 0) throw new IllegalStateException("Stack is empty.");
+ }
+
+ /**
+ * Returns the top element of the stack without affecting the stack.
+ *
+ * @return top element on the stack
+ * @throws IllegalStateException if the stack is empty
+ */
+ @SuppressWarnings("unchecked")
+ public E peek()
+ {
+ checkIfEmpty();
+
+ return (E) items[index];
+ }
+
+ /**
+ * Describes the stack, listing the element in order of depth (top element first).
+ *
+ * @return string description of the stack
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder("Stack[");
+
+ for (int i = index; i >= 0; i--)
+ {
+ if (i != index) builder.append(", ");
+
+ builder.append(String.valueOf(items[i]));
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+
+ /**
+ * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in
+ * the stack, the last object is the most shallowest (most recently pushed onto the stack). The returned array may
+ * be manipulated (it is a copy).
+ *
+ * @return the stack as an object array
+ */
+ public Object[] getSnapshot()
+ {
+ Object[] result = new Object[index + 1];
+
+ System.arraycopy(items, 0, result, 0, index + 1);
+
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g b/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
deleted file mode 100644
index 3b52ba9..0000000
--- a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 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.
-
-lexer grammar PropertyExpressionLexer;
-
-
-options
-{
- superClass='org.apache.tapestry5.internal.antlr.BaseLexer';
-}
-
-@header
-{
-package org.apache.tapestry5.internal.antlr;
-}
-
-
-// Integer constant
-fragment INTEGER
- : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
-
-// Read a property or invoke a method.
-fragment DEREF
- : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
-
-// Range operator, ".." between two integers.
-fragment RANGEOP
- : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
-
-// Decimal number
-fragment DECIMAL
- : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
-
-fragment LETTER
- : ('a'..'z'|'A'..'Z');
-fragment DIGIT
- : '0'..'9';
-fragment SIGN
- : ('+'|'-');
-LPAREN : '(';
-RPAREN : ')';
-LBRACKET: '[';
-RBRACKET: ']';
-COMMA : ',';
-BANG : '!';
-LBRACE : '{';
-RBRACE : '}';
-COLON : ':';
-
-fragment QUOTE
- : '\'';
-
-// Clumsy but effective approach to case-insensitive identifiers.
-
-fragment A
- : ('a' | 'A');
-fragment E
- : ('e' | 'E');
-fragment F
- : ('f' | 'F');
-fragment H
- : ('h' | 'H');
-fragment I
- : ('i' | 'I');
-fragment L
- : ('l' | 'L');
-fragment N
- : ('n'|'N');
-fragment R
- : ('r' | 'R');
-fragment S
- : ('s' | 'S');
-fragment T
- : ('t' | 'T');
-fragment U
- : ('u' | 'U');
-
-// Identifiers are case insensitive
-
-NULL : N U L L;
-TRUE : T R U E;
-FALSE : F A L S E;
-THIS : T H I S;
-
-IDENTIFIER
- : JAVA_ID_START (JAVA_ID_PART)*
- ;
-
-fragment
-JAVA_ID_START
- : '\u0024'
- | '\u0041'..'\u005a'
- | '\u005f'
- | '\u0061'..'\u007a'
- | '\u00c0'..'\u00d6'
- | '\u00d8'..'\u00f6'
- | '\u00f8'..'\u00ff'
- | '\u0100'..'\u1fff'
- | '\u3040'..'\u318f'
- | '\u3300'..'\u337f'
- | '\u3400'..'\u3d2d'
- | '\u4e00'..'\u9fff'
- | '\uf900'..'\ufaff'
- ;
-
-fragment
-JAVA_ID_PART
- : JAVA_ID_START
- | '\u0030'..'\u0039'
- ;
-
-
-// The Safe Dereference operator understands not to de-reference through
-// a null.
-
-SAFEDEREF
- : '?.';
-
-WS : (' '|'\t'|'\n'|'\r')+ { skip(); };
-
-
-// Literal strings are always inside single quotes.
-STRING
- : QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); };
-
-
-// Special rule that uses parsing tricks to identify numbers and ranges; it's all about
-// the dot ('.').
-// Recognizes:
-// '.' as DEREF
-// '..' as RANGEOP
-// INTEGER (sign? digit+)
-// DECIMAL (sign? digits* . digits+)
-// Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10").
-
-NUMBER_OR_RANGEOP
- : SIGN? DIGIT+
- (
- { input.LA(2) != '.' }? => '.' DIGIT* { $type = DECIMAL; stripLeadingPlus(); }
- | { $type = INTEGER; stripLeadingPlus(); }
- )
-
- | SIGN '.' DIGIT+ { $type = DECIMAL; stripLeadingPlus(); }
-
- | '.'
- (
- DIGIT+ { $type = DECIMAL; stripLeadingPlus();}
- | '.' {$type = RANGEOP; }
- | {$type = DEREF; }
- )
- ;
-
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g b/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
deleted file mode 100644
index 14753e6..0000000
--- a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2008, 2009, 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.
-
-parser grammar PropertyExpressionParser;
-
-
-options
-{
- superClass='org.apache.tapestry5.internal.antlr.BaseParser';
- output=AST;
- ASTLabelType=CommonTree;
- tokenVocab=PropertyExpressionLexer;
- backtrack=true;
-}
-
-tokens
-{
- // Parser token representing a method invocation
- INVOKE;
- // A List (top level, or as method parameter)
- LIST;
- //A Map (top level, or as method parameter)
- MAP;
- // Not operation (invert a boolean)
- NOT;
-}
-
-@header
-{
-package org.apache.tapestry5.internal.antlr;
-}
-
-
-start : expression^ EOF!;
-
-expression
- : keyword
- | rangeOp
- | constant
- | propertyChain
- | list
- | notOp
- | map
- ;
-
-keyword : NULL | TRUE | FALSE | THIS;
-
-constant: INTEGER| DECIMAL | STRING;
-
-propertyChain
- : term DEREF propertyChain -> ^(DEREF term propertyChain)
- | term SAFEDEREF propertyChain -> ^(SAFEDEREF term propertyChain)
- | term
- ;
-
-term : IDENTIFIER
- | methodInvocation
- ;
-
-methodInvocation
- : id=IDENTIFIER LPAREN RPAREN -> ^(INVOKE $id)
- | id=IDENTIFIER LPAREN expressionList RPAREN -> ^(INVOKE $id expressionList)
- ;
-
-expressionList
- : expression (COMMA! expression)*
- ;
-
-rangeOp
- : from=rangeopArg RANGEOP to=rangeopArg -> ^(RANGEOP $from $to)
- ;
-
-rangeopArg
- : INTEGER
- | propertyChain
- ;
-
-list : LBRACKET RBRACKET -> ^(LIST)
- | LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
- ;
-
-notOp : BANG expression -> ^(NOT expression)
- ;
-
-map : LBRACE RBRACE -> ^(MAP)
- | LBRACE mapEntryList RBRACE -> ^(MAP mapEntryList)
- ;
-
-mapEntryList : mapEntry (COMMA! mapEntry)*;
-
-mapEntry : mapKey COLON! expression;
-
-mapKey : keyword | constant | propertyChain;
-
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
deleted file mode 100644
index 442240d..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2008, 2009 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.antlr;
-
-import org.antlr.runtime.CharStream;
-import org.antlr.runtime.Lexer;
-import org.antlr.runtime.RecognizerSharedState;
-import org.antlr.runtime.RecognitionException;
-
-public abstract class BaseLexer extends Lexer
-{
- protected BaseLexer()
- {
- }
-
- protected BaseLexer(CharStream charStream,
- RecognizerSharedState recognizerSharedState)
- {
- super(charStream, recognizerSharedState);
- }
-
- protected void stripLeadingPlus()
- {
- String text = getText();
-
- // For compatibility with Tapestry 5.0, we need to allow a sign of '+', which Long.parseLong()
- // doesn't accept. To keep things downstream simple, we eliminate the '+' here.
-
- if (text.startsWith("+"))
- {
- setText(text.substring(1));
- }
- }
-
- @Override
- public void reportError(RecognitionException e)
- {
- throw new RuntimeException(String.format("Unable to parse input at character position %d",
- e.charPositionInLine + 1),
- e);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
deleted file mode 100644
index 212b782..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2009 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.antlr;
-
-import org.antlr.runtime.Parser;
-import org.antlr.runtime.TokenStream;
-import org.antlr.runtime.RecognizerSharedState;
-
-public class BaseParser extends Parser
-{
- public BaseParser(TokenStream tokenStream)
- {
- super(tokenStream);
- }
-
- public BaseParser(TokenStream tokenStream,
- RecognizerSharedState recognizerSharedState)
- {
- super(tokenStream, recognizerSharedState);
- }
-
- @Override
- public void emitErrorMessage(String message)
- {
- // This is caught and more properly reported later.
- throw new RuntimeException(message);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
deleted file mode 100644
index 55be313..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2012 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.
-
-/**
- * [INTERNAL USE ONLY] support classes related to Antlr; API subject to change
- */
-package org.apache.tapestry5.internal.antlr;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
deleted file mode 100644
index 924b570..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 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.internal.services;
-
-import java.lang.annotation.*;
-
-/**
- * Special annotation that is applied to literal {@link org.apache.tapestry5.PropertyConduit}s, to inform {@link
- * org.apache.tapestry5.internal.bindings.PropBinding} that the value is, in fact, invariant.
- */
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface Invariant
-{
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
deleted file mode 100644
index 1fffd4f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2008, 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 java.lang.reflect.Type;
-
-import org.apache.tapestry5.internal.InternalPropertyConduit;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-
-/**
- * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
- */
-public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
-{
- private final Class propertyType;
-
- private final AnnotationProvider annotationProvider;
-
- private final String description;
-
- private final Object value;
-
- public LiteralPropertyConduit(TypeCoercer typeCoercer, Class propertyType, AnnotationProvider annotationProvider,
- String description, Object value)
- {
- super(typeCoercer);
-
- this.propertyType = propertyType;
- this.annotationProvider = annotationProvider;
- this.description = description;
-
- this.value = value;
- }
-
- public Object get(Object instance)
- {
- return value;
- }
-
- public void set(Object instance, Object value)
- {
- throw new RuntimeException("Literal values are not updateable.");
- }
-
- public Class getPropertyType()
- {
- return propertyType;
- }
-
- public Type getPropertyGenericType()
- {
- return propertyType;
- }
-
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationProvider.getAnnotation(annotationClass);
- }
-
- public String getPropertyName()
- {
- return null;
- }
-
- @Override
- public String toString()
- {
- return description;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
deleted file mode 100644
index 765c0bb..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 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.internal.services;
-
-/**
- * Exception thrown when there is a problem parsing a property expression using the ANTLR property expression grammar.
- */
-public class PropertyExpressionException extends RuntimeException
-{
- private final String expression;
-
- public PropertyExpressionException(String message, String expression, Throwable cause)
- {
- super(message, cause);
-
- this.expression = expression;
- }
-
- /**
- * Returns the property expression containing the error.
- */
- public String getExpression()
- {
- return expression;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
deleted file mode 100644
index 78ee5f4..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2009 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;
-
-/**
- * Creates "interned" strings that are unique for the same content. This is used for common description strings,
- * particularly those used by {@link org.apache.tapestry5.Binding} instances. The internal cache of interned strings id
- * cleared whenever the {@link org.apache.tapestry5.services.ComponentClasses} {@link
- * org.apache.tapestry5.services.InvalidationEventHub} is invalidated (i.e., when component class files change).
- *
- * @since 5.1.0.0
- */
-public interface StringInterner
-{
- /**
- * Interns a string.
- *
- * @param string the string to intern
- * @return the input string, or another string instance with the same content
- */
- String intern(String string);
-
- /**
- * Formats a string (using {@link String#format(String, Object[])}) and returns the interned result.
- *
- * @param format string format
- * @param arguments used inside the format
- * @return formatted and interned string
- */
- String format(String format, Object... arguments);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
deleted file mode 100644
index e7990fc..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2006, 2008, 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.ioc;
-
-/**
- * Interface used to encapsulate any strategy used defer the creation of some object until just as needed.
- */
-public interface ObjectCreator<T>
-{
- /**
- * Create and return the object. In some limited circumstances, the implementation may cache the result, returning
- * the same object for repeated calls.
- */
- T createObject();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
deleted file mode 100644
index ffc9490..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.ioc.annotations;
-
-import java.lang.annotation.*;
-
-@Target({ElementType.METHOD, ElementType.FIELD})
-@Retention(RetentionPolicy.CLASS)
-@Documented
-public @interface IncompatibleChange
-{
- /**
- * Identifies the release in which the signature of the method was modified.
- *
- * @return a release number, e.g., "5.4"
- */
- String release();
-
- /**
- * Short string describing what changed.
- */
- String details();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
deleted file mode 100644
index 75e93e4..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2011, 2012 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.ioc.services;
-
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
-import org.apache.tapestry5.plastic.ClassInstantiator;
-import org.apache.tapestry5.plastic.PlasticClassListenerHub;
-import org.apache.tapestry5.plastic.PlasticClassTransformation;
-import org.apache.tapestry5.plastic.PlasticClassTransformer;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
-/**
- * A service used to create proxies of varying types. As a secondary concern, manages to identify the
- * location of methods and constructors, which is important for exception reporting.
- *
- * @since 5.3
- */
-public interface PlasticProxyFactory extends PlasticClassListenerHub
-{
- /**
- * Returns the class loader used when creating new classes, this is a child class loader
- * of another class loader (usually, the thread's context class loader).
- */
- ClassLoader getClassLoader();
-
- /**
- * Creates a proxy object that implements the indicated interface, then invokes the callback to further
- * configure the proxy.
- *
- * @param interfaceType
- * interface implemented by proxy
- * @param callback
- * configures the proxy
- * @return instantiator that can be used to create an instance of the proxy class
- */
- <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
-
- /**
- * Creates a proxy object that implements the indicated interface and indicated service implementation type,
- * then invokes the callback to further configure the proxy.
- *
- * @param interfaceType
- * interface implemented by proxy
- * @param implementationType
- * a class that implements the interfaceType. It can be null.
- * @param callback
- * configures the proxy
- * @return instantiator that can be used to create an instance of the proxy class
- */
- @IncompatibleChange(release = "5.4", details = "TAP5-2029")
- <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
-
- /**
- * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
- * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
- * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
- *
- * @param interfaceType
- * class proxy will extend from
- * @return transformation from which an instantiator may be created
- */
- <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
-
- /**
- * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
- * implementation class. This should only be
- * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
- * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
- *
- * @param interfaceType
- * class proxy will extend from
- * @param implementationType
- * a class that implements the interfaceType. It can be null.
- * @return transformation from which an instantiator may be created
- */
- @IncompatibleChange(release = "5.4", details = "TAP5-2029")
- <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
-
- /**
- * Creates a proxy instance that delegates all methods through a corresponding
- * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
- * creator implementation may decide to
- * cache the return value as appropriate).
- *
- * @param <T>
- * type of proxy
- * @param interfaceType
- * interface class for proxy
- * @param creator
- * object responsible for creating the real object
- * @param description
- * the <code>toString()</code> of the proxy
- * @return proxy instance
- */
- <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
-
- /**
- * Creates a proxy instance that delegates all methods through a corresponding
- * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
- * creator implementation may decide to
- * cache the return value as appropriate).
- *
- * @param <T>
- * type of proxy
- * @param interfaceType
- * interface class for proxy
- * @param implementationType
- * class that implements the interface type. It may be null
- * @param creator
- * object responsible for creating the real object
- * @param description
- * the <code>toString()</code> of the proxy
- * @return proxy instance
- */
- @IncompatibleChange(release = "5.4", details = "Added for TAP5-2029")
- <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
-
- /**
- * Converts a method to a {@link Location}, which includes information about the source file name and line number.
- *
- * @param method
- * to look up
- * @return the location (identifying the method and possibly, the line number within the method)
- */
- Location getMethodLocation(Method method);
-
- /**
- * Return a string representation for the constructor (including class and parameters) and (if available) file name
- * and line number.
- *
- * @return the location (identifying the constructor and possibly, the line number within the method)
- */
- Location getConstructorLocation(Constructor constructor);
-
- /**
- * Clears any cached information stored by the proxy factory; this is useful in Tapestry development mode
- * when a class loader may have been discarded (because the proxy factory may indirectly keep references
- * to classes loaded by the old class loader).
- *
- * @since 5.3.3
- */
- void clearCache();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
deleted file mode 100644
index cfa13a0..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2007, 2008, 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.ioc.util;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-
-/**
- * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe.
- *
- * @param <E> the type of elements stored in the map
- * @see CollectionFactory#newStack()
- */
-public class Stack<E>
-{
- private static final int MINIMUM_SIZE = 3;
-
- private static final int DEFAULT_ARRAY_SIZE = 20;
-
- private Object[] items;
-
- private int index = -1;
-
- /**
- * Normal constructor supporting an initial size of 20.
- */
- public Stack()
- {
- this(DEFAULT_ARRAY_SIZE);
- }
-
- /**
- * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best
- * efficiency, set this to the maximum depth of the stack.
- */
- public Stack(int initialSize)
- {
- items = new Object[Math.max(initialSize, MINIMUM_SIZE)];
- }
-
- /**
- * Returns true if the stack is empty.
- */
- public boolean isEmpty()
- {
- return index < 0;
- }
-
- /**
- * Returns the number of items currently in the stack.
- */
- public int getDepth()
- {
- return index + 1;
- }
-
- /**
- * Clears the stack, the same as popping off all elements.
- */
- public void clear()
- {
- for (int i = 0; i <= index; i++) items[i] = null;
-
- index = -1;
- }
-
- /**
- * Pushes a new item onto the stack.
- */
- public void push(E item)
- {
- index++;
-
- if (index == items.length)
- {
- int newCapacity = (items.length * 3) / 2 + 1;
- Object[] newItems = new Object[newCapacity];
- System.arraycopy(items, 0, newItems, 0, items.length);
-
- items = newItems;
- }
-
- items[index] = item;
- }
-
- /**
- * Pops the top element off the stack and returns it.
- *
- * @return the top element of the stack
- * @throws IllegalStateException if the stack is empty
- */
- @SuppressWarnings("unchecked")
- public E pop()
- {
- checkIfEmpty();
-
- Object result = items[index];
-
- items[index] = null;
-
- index--;
-
- return (E) result;
- }
-
- private void checkIfEmpty()
- {
- if (index < 0) throw new IllegalStateException("Stack is empty.");
- }
-
- /**
- * Returns the top element of the stack without affecting the stack.
- *
- * @return top element on the stack
- * @throws IllegalStateException if the stack is empty
- */
- @SuppressWarnings("unchecked")
- public E peek()
- {
- checkIfEmpty();
-
- return (E) items[index];
- }
-
- /**
- * Describes the stack, listing the element in order of depth (top element first).
- *
- * @return string description of the stack
- */
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder("Stack[");
-
- for (int i = index; i >= 0; i--)
- {
- if (i != index) builder.append(", ");
-
- builder.append(String.valueOf(items[i]));
- }
-
- builder.append("]");
-
- return builder.toString();
- }
-
- /**
- * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in
- * the stack, the last object is the most shallowest (most recently pushed onto the stack). The returned array may
- * be manipulated (it is a copy).
- *
- * @return the stack as an object array
- */
- public Object[] getSnapshot()
- {
- Object[] result = new Object[index + 1];
-
- System.arraycopy(items, 0, result, 0, index + 1);
-
- return result;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
new file mode 100644
index 0000000..ffc9490
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
@@ -0,0 +1,33 @@
+// 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.ioc.annotations;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.CLASS)
+@Documented
+public @interface IncompatibleChange
+{
+ /**
+ * Identifies the release in which the signature of the method was modified.
+ *
+ * @return a release number, e.g., "5.4"
+ */
+ String release();
+
+ /**
+ * Short string describing what changed.
+ */
+ String details();
+}
[15/15] tapestry-5 git commit: Fifth pass creating the BeanModel and
Commons packages. Initial testing looks good.
Posted by th...@apache.org.
Fifth pass creating the BeanModel and Commons packages. Initial testing looks good.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/696bc7ae
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/696bc7ae
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/696bc7ae
Branch: refs/heads/beanmodel-split
Commit: 696bc7ae848f4b4f2421ff77ceb4858a2f10465c
Parents: eb7ec86
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 20:29:20 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 20:29:20 2014 -0200
----------------------------------------------------------------------
.../org/apache/tapestry5/PropertyConduit2.java | 2 +-
.../beaneditor/BeanModelSourceBuilder.java | 159 ++---
.../CoercingPropertyConduitWrapper.java | 8 +-
.../services/LiteralPropertyConduit.java | 2 +-
.../services/PropertyConduitSourceImpl.java | 46 +-
.../services/ClassPropertyAdapterImpl.java | 92 +--
.../services/AnnotationDataTypeAnalyzer.java | 32 +
.../ioc/internal/BasicDataTypeAnalyzers.java | 151 +++++
.../ioc/internal/util/InternalCommonsUtils.java | 608 +++++++++----------
.../internal/TapestryInternalUtils.java | 4 +-
.../internal/bindings/AbstractBinding.java | 2 +-
.../internal/bindings/PropBinding.java | 8 +-
.../services/AnnotationDataTypeAnalyzer.java | 32 -
.../InternalComponentResourcesImpl.java | 4 +-
.../tapestry5/modules/TapestryModule.java | 14 +-
.../app1/components/GenericTypeDisplay.java | 34 +-
.../integration/app1/pages/GenericTypeDemo.java | 24 +-
.../pages/GridWithSubmitWithContextDemo.java | 4 +-
.../integration/app2/base/ChildBasePage.java | 8 +-
.../integration/app2/base/ParentBasePage.java | 2 +-
.../pagelevel/OverrideMethodsTest.java | 14 +-
.../services/PropertyConduitSourceImplTest.java | 34 +-
.../org/apache/tapestry5/json/JSONArray.java | 2 +-
.../org/apache/tapestry5/json/JSONObject.java | 2 +-
24 files changed, 723 insertions(+), 565 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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
index 839d70f..1577a3d 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
@@ -36,5 +36,5 @@ public interface PropertyConduit2 extends PropertyConduit
* @see java.lang.reflect.Field#getGenericType()
*
*/
- Type getPropertyGenericType();
+ Type getPropertyGenericType();
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
index 8cef66e..4ac3373 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
@@ -15,15 +15,22 @@ package org.apache.tapestry5.beaneditor;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
import javax.naming.OperationNotSupportedException;
+import javax.swing.JFrame;
import org.apache.tapestry5.internal.services.BeanModelSourceImpl;
import org.apache.tapestry5.internal.services.PropertyConduitSourceImpl;
import org.apache.tapestry5.internal.services.StringInterner;
import org.apache.tapestry5.internal.services.StringInternerImpl;
import org.apache.tapestry5.ioc.Configuration;
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
import org.apache.tapestry5.ioc.internal.services.PropertyAccessImpl;
@@ -31,6 +38,7 @@ import org.apache.tapestry5.ioc.internal.services.TypeCoercerImpl;
import org.apache.tapestry5.ioc.services.CoercionTuple;
import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
import org.apache.tapestry5.ioc.services.PropertyAccess;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.services.BeanModelSource;
import org.apache.tapestry5.services.DataTypeAnalyzer;
@@ -42,80 +50,89 @@ import org.slf4j.LoggerFactory;
* Tapestry-IoC. Usage of Tapestry-IoC is still recommended.
*/
public class BeanModelSourceBuilder {
-
- private TypeCoercer typeCoercer;
- private PropertyAccess propertyAccess;
- private PropertyConduitSource propertyConduitSource;
- private PlasticProxyFactory plasticProxyFactory;
- private DataTypeAnalyzer dataTypeAnalyzer;
- private ObjectLocator objectLocator;
- private StringInterner stringInterner;
- /**
- * Sets the {@link TypeCoercer} to be used.
- */
- public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer) {
- this.typeCoercer = typeCoercer;
-// propertyAccess = new PropertyAcc
- return this;
- }
+ private TypeCoercer typeCoercer;
+ private PropertyAccess propertyAccess;
+ private PropertyConduitSource propertyConduitSource;
+ private PlasticProxyFactory plasticProxyFactory;
+ private DataTypeAnalyzer dataTypeAnalyzer;
+ private ObjectLocator objectLocator;
+ private StringInterner stringInterner;
- public BeanModelSource build()
- {
-
- if (typeCoercer == null)
- {
- createTypeCoercer();
- }
-
- if (propertyAccess == null)
- {
- propertyAccess = new PropertyAccessImpl();
- }
-
- if (stringInterner == null)
- {
- stringInterner = new StringInternerImpl();
- }
-
- if (plasticProxyFactory == null)
- {
- plasticProxyFactory = new PlasticProxyFactoryImpl(getClass().getClassLoader(), LoggerFactory.getLogger(PlasticProxyFactory.class));
- }
-
- if (propertyConduitSource == null)
- {
- propertyConduitSource = new PropertyConduitSourceImpl(propertyAccess, plasticProxyFactory, typeCoercer, stringInterner);
- }
-
- return new BeanModelSourceImpl(typeCoercer, propertyAccess, propertyConduitSource, plasticProxyFactory, dataTypeAnalyzer, objectLocator);
-
- }
+ /**
+ * Sets the {@link TypeCoercer} to be used.
+ */
+ public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer)
+ {
+ this.typeCoercer = typeCoercer;
+ return this;
+ }
- private void createTypeCoercer() {
- CoercionTupleConfiguration configuration = new CoercionTupleConfiguration();
- BasicTypeCoercions.provideBasicTypeCoercions(configuration);
- typeCoercer = new TypeCoercerImpl(configuration.getTuples());
- }
-
- final private static class CoercionTupleConfiguration implements Configuration<CoercionTuple> {
-
- final private Collection<CoercionTuple> tuples = new ArrayList<CoercionTuple>();
+ public BeanModelSource build()
+ {
+
+ if (typeCoercer == null)
+ {
+ createTypeCoercer();
+ }
+
+ if (propertyAccess == null)
+ {
+ propertyAccess = new PropertyAccessImpl();
+ }
+
+ if (dataTypeAnalyzer == null)
+ {
+ dataTypeAnalyzer = BasicDataTypeAnalyzers.createDefaultDataTypeAnalyzer();
+ }
+
+ if (stringInterner == null)
+ {
+ stringInterner = new StringInternerImpl();
+ }
+
+ if (plasticProxyFactory == null)
+ {
+ plasticProxyFactory = new PlasticProxyFactoryImpl(getClass().getClassLoader(), LoggerFactory.getLogger(PlasticProxyFactory.class));
+ }
+
+ if (propertyConduitSource == null)
+ {
+ propertyConduitSource = new PropertyConduitSourceImpl(propertyAccess, plasticProxyFactory, typeCoercer, stringInterner);
+ }
+
+ return new BeanModelSourceImpl(typeCoercer, propertyAccess, propertyConduitSource, plasticProxyFactory, dataTypeAnalyzer, objectLocator);
+
+ }
+ private void createTypeCoercer()
+ {
+ CoercionTupleConfiguration configuration = new CoercionTupleConfiguration();
+ BasicTypeCoercions.provideBasicTypeCoercions(configuration);
+ typeCoercer = new TypeCoercerImpl(configuration.getTuples());
+ }
- @Override
- public void add(CoercionTuple tuble) {
- tuples.add(tuble);
- }
+ final private static class CoercionTupleConfiguration implements Configuration<CoercionTuple>
+ {
+
+ final private Collection<CoercionTuple> tuples = new ArrayList<CoercionTuple>();
+
+ @Override
+ public void add(CoercionTuple tuble)
+ {
+ tuples.add(tuble);
+ }
+
+ @Override
+ public void addInstance(Class<? extends CoercionTuple> clazz)
+ {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Collection<CoercionTuple> getTuples()
+ {
+ return tuples;
+ }
+
+ }
- @Override
- public void addInstance(Class<? extends CoercionTuple> clazz) {
- throw new RuntimeException("Not implemented");
- }
-
- public Collection<CoercionTuple> getTuples() {
- return tuples;
- }
-
- }
-
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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
index 4dbfb2d..2127696 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
@@ -50,10 +50,10 @@ public class CoercingPropertyConduitWrapper implements PropertyConduit2
public Type getPropertyGenericType()
{
- if (conduit instanceof PropertyConduit2) {
- return ((PropertyConduit2) conduit).getPropertyGenericType();
- }
- return conduit.getPropertyType();
+ if (conduit instanceof PropertyConduit2) {
+ return ((PropertyConduit2) conduit).getPropertyGenericType();
+ }
+ return conduit.getPropertyType();
}
@SuppressWarnings("unchecked")
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
index 1fffd4f..e8cd58f 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
@@ -63,7 +63,7 @@ public class LiteralPropertyConduit extends PropertyConduitDelegate implements I
public Type getPropertyGenericType()
{
- return propertyType;
+ return propertyType;
}
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 09d234c..9148b46 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -524,28 +524,28 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
private Type getGenericType(PropertyAdapter adapter)
{
- Type genericType = null;
- if (adapter.getField() != null)
- {
- genericType = adapter.getField().getGenericType();
- }
- else if (adapter.getReadMethod() != null)
- {
- genericType = adapter.getReadMethod().getGenericReturnType();
- }
- else if (adapter.getWriteMethod() != null)
- {
- genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
- }
- else
- {
- throw new RuntimeException("Could not find accessor for property " + adapter.getName());
- }
-
- return genericType == null ? adapter.getType() : genericType;
- }
-
- private void implementSetter(PropertyAdapter adapter)
+ Type genericType = null;
+ if (adapter.getField() != null)
+ {
+ genericType = adapter.getField().getGenericType();
+ }
+ else if (adapter.getReadMethod() != null)
+ {
+ genericType = adapter.getReadMethod().getGenericReturnType();
+ }
+ else if (adapter.getWriteMethod() != null)
+ {
+ genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
+ }
+ else
+ {
+ throw new RuntimeException("Could not find accessor for property " + adapter.getName());
+ }
+
+ return genericType == null ? adapter.getType() : genericType;
+ }
+
+ private void implementSetter(PropertyAdapter adapter)
{
if (adapter.getWriteMethod() != null)
{
@@ -1488,7 +1488,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
public Type getPropertyGenericType()
{
- return rootClass;
+ return rootClass;
}
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
index 5d6dfec..9c5f36c4 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
@@ -57,11 +57,11 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
// TAP5-1493
if (readMethod != null && readMethod.isBridge())
{
- if (nonBridgeMethods == null)
- {
- nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
- }
- readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods);
+ if (nonBridgeMethods == null)
+ {
+ nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+ }
+ readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods);
}
// TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed
@@ -86,11 +86,11 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
if (writeMethod != null && writeMethod.isBridge())
{
- if (nonBridgeMethods == null)
- {
- nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
- }
- writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
+ if (nonBridgeMethods == null)
+ {
+ nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+ }
+ writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
}
// TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed
@@ -149,24 +149,24 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
* (default to providedmethod if none found)
*/
private Method findMethodWithSameNameAndParamCount(Method method, Map<String, List<Method>> groupedMethods) {
- List<Method> methodGroup = groupedMethods.get(method.getName());
- if (methodGroup != null)
- {
- for (Method nonBridgeMethod : methodGroup)
- {
- if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length)
- {
- // return the non-bridge method with the same name / argument count
- return nonBridgeMethod;
- }
- }
- }
-
- // default to the provided method
- return method;
- }
-
- /**
+ List<Method> methodGroup = groupedMethods.get(method.getName());
+ if (methodGroup != null)
+ {
+ for (Method nonBridgeMethod : methodGroup)
+ {
+ if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length)
+ {
+ // return the non-bridge method with the same name / argument count
+ return nonBridgeMethod;
+ }
+ }
+ }
+
+ // default to the provided method
+ return method;
+ }
+
+ /**
* Find all of the public methods that are not bridge methods and
* group them by method name
*
@@ -176,24 +176,24 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
*/
private Map<String, List<Method>> groupNonBridgeMethodsByName(Class type)
{
- Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap();
- for (Method method : type.getMethods())
- {
- if (!method.isBridge())
- {
- List<Method> methodGroup = methodGroupsByName.get(method.getName());
- if (methodGroup == null)
- {
- methodGroup = CollectionFactory.newList();
- methodGroupsByName.put(method.getName(), methodGroup);
- }
- methodGroup.add(method);
- }
- }
- return methodGroupsByName;
- }
-
- @Override
+ Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap();
+ for (Method method : type.getMethods())
+ {
+ if (!method.isBridge())
+ {
+ List<Method> methodGroup = methodGroupsByName.get(method.getName());
+ if (methodGroup == null)
+ {
+ methodGroup = CollectionFactory.newList();
+ methodGroupsByName.put(method.getName(), methodGroup);
+ }
+ methodGroup.add(method);
+ }
+ }
+ return methodGroupsByName;
+ }
+
+ @Override
public Class getBeanType()
{
return beanType;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java b/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
new file mode 100644
index 0000000..8b20666
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
@@ -0,0 +1,32 @@
+// 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 org.apache.tapestry5.beaneditor.DataType;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+
+/**
+ * Checks for the {@link DataType} annotation, returning its value if present.
+ */
+public class AnnotationDataTypeAnalyzer implements DataTypeAnalyzer
+{
+ public String identifyDataType(PropertyAdapter adapter)
+ {
+ DataType annotation = adapter.getAnnotation(DataType.class);
+
+ return annotation == null ? null : annotation.value();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
new file mode 100644
index 0000000..df7564f
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
@@ -0,0 +1,151 @@
+// Copyright 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.ioc.internal;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tapestry5.beaneditor.DataTypeConstants;
+import org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer;
+import org.apache.tapestry5.ioc.MappedConfiguration;
+import org.apache.tapestry5.ioc.OrderedConfiguration;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+
+/**
+ * Class that provides Tapestry's basic default data type analyzers.
+ */
+public class BasicDataTypeAnalyzers
+{
+
+ public static void contributeDataTypeAnalyzer(
+ OrderedConfiguration<DataTypeAnalyzer> configuration,
+ DataTypeAnalyzer defaultDataTypeAnalyzer) {
+ configuration.add("Annotation", new AnnotationDataTypeAnalyzer());
+ if (defaultDataTypeAnalyzer == null)
+ {
+ defaultDataTypeAnalyzer = createDefaultDataTypeAnalyzer();
+ }
+ configuration.add("Default", defaultDataTypeAnalyzer, "after:*");
+ }
+
+ public static DataTypeAnalyzer createDefaultDataTypeAnalyzer()
+ {
+ DefaultDataTypeAnalyzerMappedConfiguration mappedConfiguration = new DefaultDataTypeAnalyzerMappedConfiguration();
+ provideDefaultDataTypeAnalyzers(mappedConfiguration);
+ return new CombinedDataTypeAnalyzer(new AnnotationDataTypeAnalyzer(), new MapDataTypeAnalyzer(mappedConfiguration.getMap()));
+ }
+
+ /**
+ * Maps property types to data type names:
+ * <ul>
+ * <li>String --> text
+ * <li>Number --> number
+ * <li>Enum --> enum
+ * <li>Boolean --> boolean
+ * <li>Date --> date
+ * </ul>
+ */
+ public static void provideDefaultDataTypeAnalyzers(MappedConfiguration<Class, String> configuration)
+ {
+ // This is a special case contributed to avoid exceptions when a
+ // property type can't be
+ // matched. DefaultDataTypeAnalyzer converts the empty string to null.
+
+ configuration.add(Object.class, "");
+
+ configuration.add(String.class, DataTypeConstants.TEXT);
+ configuration.add(Number.class, DataTypeConstants.NUMBER);
+ configuration.add(Enum.class, DataTypeConstants.ENUM);
+ configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
+ configuration.add(Date.class, DataTypeConstants.DATE);
+ configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
+ }
+
+ final private static class DefaultDataTypeAnalyzerMappedConfiguration implements MappedConfiguration<Class, String>
+ {
+
+ final Map<Class, String> map = new HashMap<Class, String>();
+
+ @Override
+ public void add(Class key, String value) {
+ map.put(key, value);
+ }
+
+ @Override
+ public void override(Class key, String value) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public void addInstance(Class key, Class<? extends String> clazz) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public void overrideInstance(Class key, Class<? extends String> clazz) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Map<Class, String> getMap() {
+ return map;
+ }
+
+ }
+
+ final private static class MapDataTypeAnalyzer implements DataTypeAnalyzer
+ {
+
+ final Map<Class, String> map;
+
+ public MapDataTypeAnalyzer(Map<Class, String> map) {
+ this.map = map;
+ }
+
+ @Override
+ public String identifyDataType(PropertyAdapter adapter) {
+ return map.get(adapter.getType());
+ }
+
+ }
+
+ final private static class CombinedDataTypeAnalyzer implements DataTypeAnalyzer
+ {
+
+ final private DataTypeAnalyzer first, second;
+
+ public CombinedDataTypeAnalyzer(DataTypeAnalyzer first, DataTypeAnalyzer second)
+ {
+ super();
+ this.first = first;
+ this.second = second;
+ }
+
+ @Override
+ public String identifyDataType(PropertyAdapter adapter)
+ {
+ String type = first.identifyDataType(adapter);
+ if (type == null)
+ {
+ type = second.identifyDataType(adapter);
+ }
+ return type;
+ }
+
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
index 3c391e0..2bc33d8 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -33,11 +33,11 @@ import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
*/
public class InternalCommonsUtils {
- /**
- * @since 5.3
- */
- public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
- private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+ /**
+ * @since 5.3
+ */
+ public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+ private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
/**
* Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
@@ -67,322 +67,322 @@ public class InternalCommonsUtils {
list.add(value);
}
- /**
- * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
- * convertable to a location.
- */
-
- public static Location locationOf(Object location)
- {
- if (location == null)
- return null;
-
- if (location instanceof Location)
- return (Location) location;
-
- if (location instanceof Locatable)
- return ((Locatable) location).getLocation();
-
- return null;
- }
+ /**
+ * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+ * convertable to a location.
+ */
+
+ public static Location locationOf(Object location)
+ {
+ if (location == null)
+ return null;
+
+ if (location instanceof Location)
+ return (Location) location;
+
+ if (location instanceof Locatable)
+ return ((Locatable) location).getLocation();
+
+ return null;
+ }
- public static AnnotationProvider toAnnotationProvider(final Method element)
- {
- if (element == null)
- return NULL_ANNOTATION_PROVIDER;
-
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return element.getAnnotation(annotationClass);
- }
- };
- }
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
- /**
- * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
- * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
- * underscore).
- *
- * @param expression a property expression
- * @return the expression with punctuation removed
- */
- public static String extractIdFromPropertyExpression(String expression)
- {
- return replace(expression, NON_WORD_PATTERN, "");
- }
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
- public static String replace(String input, Pattern pattern, String replacement)
- {
- return pattern.matcher(input).replaceAll(replacement);
- }
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
- /**
- * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
- * user presentable form.
- */
- public static String defaultLabel(String id, Messages messages, String propertyExpression)
- {
- String key = id + "-label";
-
- if (messages.contains(key))
- return messages.get(key);
-
- return toUserPresentable(extractIdFromPropertyExpression(InternalCommonsUtils.lastTerm(propertyExpression)));
- }
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalCommonsUtils.lastTerm(propertyExpression)));
+ }
- /**
- * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
- * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
- * following word), thus "user_id" also becomes "User Id".
- */
- public static String toUserPresentable(String id)
- {
- StringBuilder builder = new StringBuilder(id.length() * 2);
-
- char[] chars = id.toCharArray();
- boolean postSpace = true;
- boolean upcaseNext = true;
-
- for (char ch : chars)
- {
- if (upcaseNext)
- {
- builder.append(Character.toUpperCase(ch));
- upcaseNext = false;
-
- continue;
- }
-
- if (ch == '_')
- {
- builder.append(' ');
- upcaseNext = true;
- continue;
- }
-
- boolean upperCase = Character.isUpperCase(ch);
-
- if (upperCase && !postSpace)
- builder.append(' ');
-
- builder.append(ch);
-
- postSpace = upperCase;
- }
-
- return builder.toString();
- }
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
- /**
- * @since 5.3
- */
- public static AnnotationProvider toAnnotationProvider(final Class element)
- {
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationClass.cast(element.getAnnotation(annotationClass));
- }
- };
- }
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
- /**
- * Pattern used to eliminate leading and trailing underscores and dollar signs.
- */
- static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
- Pattern.CASE_INSENSITIVE);
+ /**
+ * Pattern used to eliminate leading and trailing underscores and dollar signs.
+ */
+ static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+ Pattern.CASE_INSENSITIVE);
- /**
- * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
- * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
- *
- * @param method
- * @return short string representation
- */
- public static String asString(Method method)
- {
- StringBuilder buffer = new StringBuilder();
-
- buffer.append(method.getDeclaringClass().getName());
- buffer.append(".");
- buffer.append(method.getName());
- buffer.append("(");
-
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- if (i > 0)
- buffer.append(", ");
-
- String name = method.getParameterTypes()[i].getSimpleName();
-
- buffer.append(name);
- }
-
- return buffer.append(")").toString();
- }
+ /**
+ * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+ * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+ *
+ * @param method
+ * @return short string representation
+ */
+ public static String asString(Method method)
+ {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append(method.getDeclaringClass().getName());
+ buffer.append(".");
+ buffer.append(method.getName());
+ buffer.append("(");
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ if (i > 0)
+ buffer.append(", ");
+
+ String name = method.getParameterTypes()[i].getSimpleName();
+
+ buffer.append(name);
+ }
+
+ return buffer.append(")").toString();
+ }
- /**
- * Strips leading "_" and "$" and trailing "_" from the name.
- */
- public static String stripMemberName(String memberName)
- {
- assert InternalCommonsUtils.isNonBlank(memberName);
- Matcher matcher = NAME_PATTERN.matcher(memberName);
-
- if (!matcher.matches())
- throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
- return matcher.group(1);
- }
+ /**
+ * Strips leading "_" and "$" and trailing "_" from the name.
+ */
+ public static String stripMemberName(String memberName)
+ {
+ assert InternalCommonsUtils.isNonBlank(memberName);
+ Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+ if (!matcher.matches())
+ throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+ return matcher.group(1);
+ }
- /**
- * Joins together some number of elements to form a comma separated list.
- */
- public static String join(List elements)
- {
- return InternalCommonsUtils.join(elements, ", ");
- }
+ /**
+ * Joins together some number of elements to form a comma separated list.
+ */
+ public static String join(List elements)
+ {
+ return InternalCommonsUtils.join(elements, ", ");
+ }
- /**
- * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
- * string "(blank)".
- *
- * @param elements
- * objects to be joined together
- * @param separator
- * used between elements when joining
- */
- public static String join(List elements, String separator)
- {
- switch (elements.size())
- {
- case 0:
- return "";
-
- case 1:
- return elements.get(0).toString();
-
- default:
-
- StringBuilder buffer = new StringBuilder();
- boolean first = true;
-
- for (Object o : elements)
- {
- if (!first)
- buffer.append(separator);
-
- String string = String.valueOf(o);
-
- if (string.equals(""))
- string = "(blank)";
-
- buffer.append(string);
-
- first = false;
- }
-
- return buffer.toString();
- }
- }
+ /**
+ * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+ * string "(blank)".
+ *
+ * @param elements
+ * objects to be joined together
+ * @param separator
+ * used between elements when joining
+ */
+ public static String join(List elements, String separator)
+ {
+ switch (elements.size())
+ {
+ case 0:
+ return "";
+
+ case 1:
+ return elements.get(0).toString();
+
+ default:
+
+ StringBuilder buffer = new StringBuilder();
+ boolean first = true;
+
+ for (Object o : elements)
+ {
+ if (!first)
+ buffer.append(separator);
+
+ String string = String.valueOf(o);
+
+ if (string.equals(""))
+ string = "(blank)";
+
+ buffer.append(string);
+
+ first = false;
+ }
+
+ return buffer.toString();
+ }
+ }
- /**
- * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
- *
- * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
- * empty
- */
- public static String joinSorted(Collection elements)
- {
- if (elements == null || elements.isEmpty())
- return "(none)";
-
- List<String> list = CollectionFactory.newList();
-
- for (Object o : elements)
- list.add(String.valueOf(o));
-
- Collections.sort(list);
-
- return join(list);
- }
+ /**
+ * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+ *
+ * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+ * empty
+ */
+ public static String joinSorted(Collection elements)
+ {
+ if (elements == null || elements.isEmpty())
+ return "(none)";
+
+ List<String> list = CollectionFactory.newList();
+
+ for (Object o : elements)
+ list.add(String.valueOf(o));
+
+ Collections.sort(list);
+
+ return join(list);
+ }
- /**
- * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
- */
-
- public static boolean isBlank(String input)
- {
- return input == null || input.length() == 0 || input.trim().length() == 0;
- }
+ /**
+ * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ */
+
+ public static boolean isBlank(String input)
+ {
+ return input == null || input.length() == 0 || input.trim().length() == 0;
+ }
- /**
- * Capitalizes a string, converting the first character to uppercase.
- */
- public static String capitalize(String input)
- {
- if (input.length() == 0)
- return input;
-
- return input.substring(0, 1).toUpperCase() + input.substring(1);
- }
+ /**
+ * Capitalizes a string, converting the first character to uppercase.
+ */
+ public static String capitalize(String input)
+ {
+ if (input.length() == 0)
+ return input;
+
+ return input.substring(0, 1).toUpperCase() + input.substring(1);
+ }
- public static boolean isNonBlank(String input)
- {
- return !isBlank(input);
- }
+ public static boolean isNonBlank(String input)
+ {
+ return !isBlank(input);
+ }
- /**
- * Return true if the input string contains the marker for symbols that must be expanded.
- */
- public static boolean containsSymbols(String input)
- {
- return input.contains("${");
- }
+ /**
+ * Return true if the input string contains the marker for symbols that must be expanded.
+ */
+ public static boolean containsSymbols(String input)
+ {
+ return input.contains("${");
+ }
- /**
- * Searches the string for the final period ('.') character and returns everything after that. The input string is
- * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
- * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
- * character.
- */
- public static String lastTerm(String input)
- {
- assert isNonBlank(input);
- int dotx = input.lastIndexOf('.');
-
- if (dotx < 0)
- return input;
-
- return input.substring(dotx + 1);
- }
+ /**
+ * Searches the string for the final period ('.') character and returns everything after that. The input string is
+ * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+ * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+ * character.
+ */
+ public static String lastTerm(String input)
+ {
+ assert isNonBlank(input);
+ int dotx = input.lastIndexOf('.');
+
+ if (dotx < 0)
+ return input;
+
+ return input.substring(dotx + 1);
+ }
- /**
- * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
- *
- * @param map
- * the map to extract keys from (may be null)
- * @return the sorted keys, or the empty set if map is null
- */
-
- public static List<String> sortedKeys(Map map)
- {
- if (map == null)
- return Collections.emptyList();
-
- List<String> keys = CollectionFactory.newList();
-
- for (Object o : map.keySet())
- keys.add(String.valueOf(o));
-
- Collections.sort(keys);
-
- return keys;
- }
+ /**
+ * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+ *
+ * @param map
+ * the map to extract keys from (may be null)
+ * @return the sorted keys, or the empty set if map is null
+ */
+
+ public static List<String> sortedKeys(Map map)
+ {
+ if (map == null)
+ return Collections.emptyList();
+
+ List<String> keys = CollectionFactory.newList();
+
+ for (Object o : map.keySet())
+ keys.add(String.valueOf(o));
+
+ Collections.sort(keys);
+
+ return keys;
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e032975..5e4ab42 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -457,9 +457,9 @@ public class TapestryInternalUtils
{
if (conduit instanceof PropertyConduit2)
{
- return ((PropertyConduit2) conduit).getPropertyGenericType();
+ return ((PropertyConduit2) conduit).getPropertyGenericType();
}
- return conduit.getPropertyType();
+ return conduit.getPropertyType();
}
public Object get(Object instance)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
index 8e731b7..572d61a 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
@@ -71,7 +71,7 @@ public abstract class AbstractBinding extends BaseLocatable implements Binding2
*/
public Type getBindingGenericType()
{
- return getBindingType();
+ return getBindingType();
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
index afe63eb..da4c53e 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
@@ -111,10 +111,10 @@ public class PropBinding extends AbstractBinding implements InternalPropBinding
@Override
public Type getBindingGenericType()
{
- if (conduit instanceof PropertyConduit2) {
- return ((PropertyConduit2) conduit).getPropertyGenericType();
- }
- return conduit.getPropertyType();
+ if (conduit instanceof PropertyConduit2) {
+ return ((PropertyConduit2) conduit).getPropertyGenericType();
+ }
+ return conduit.getPropertyType();
}
@Override
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
deleted file mode 100644
index 8b20666..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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 org.apache.tapestry5.beaneditor.DataType;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.apache.tapestry5.services.DataTypeAnalyzer;
-
-/**
- * Checks for the {@link DataType} annotation, returning its value if present.
- */
-public class AnnotationDataTypeAnalyzer implements DataTypeAnalyzer
-{
- public String identifyDataType(PropertyAdapter adapter)
- {
- DataType annotation = adapter.getAnnotation(DataType.class);
-
- return annotation == null ? null : annotation.value();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
index c51c086..5d0ac16 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
@@ -351,9 +351,9 @@ public class InternalComponentResourcesImpl extends LockSupport implements Inter
Binding binding = getBinding(parameterName);
Type genericType;
if (binding instanceof Binding2) {
- genericType = ((Binding2) binding).getBindingGenericType();
+ genericType = ((Binding2) binding).getBindingGenericType();
} else {
- genericType = binding.getBindingType();
+ genericType = binding.getBindingType();
}
return genericType;
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index e3902de..8a72a4d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -59,6 +59,7 @@ import org.apache.tapestry5.internal.util.StringRenderable;
import org.apache.tapestry5.internal.validator.ValidatorMacroImpl;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.services.*;
import org.apache.tapestry5.ioc.util.AvailableValues;
@@ -621,18 +622,7 @@ public final class TapestryModule
*/
public static void contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class, String> configuration)
{
- // This is a special case contributed to avoid exceptions when a
- // property type can't be
- // matched. DefaultDataTypeAnalyzer converts the empty string to null.
-
- configuration.add(Object.class, "");
-
- configuration.add(String.class, DataTypeConstants.TEXT);
- configuration.add(Number.class, DataTypeConstants.NUMBER);
- configuration.add(Enum.class, DataTypeConstants.ENUM);
- configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
- configuration.add(Date.class, DataTypeConstants.DATE);
- configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
+ BasicDataTypeAnalyzers.provideDefaultDataTypeAnalyzers(configuration);
}
@Contribute(BeanBlockSource.class)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
index f6d2aa7..0a9365e 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
@@ -25,21 +25,21 @@ import org.apache.tapestry5.ioc.annotations.Inject;
* Outputs the type and genericType of the 'value' binding in a div
*/
public class GenericTypeDisplay {
- @Inject
- private ComponentResources resources;
-
- @Parameter(required=true, defaultPrefix=BindingConstants.LITERAL)
- private String description;
-
- @Parameter(required=true)
- private Object value;
-
- void afterRender(MarkupWriter writer) {
- writer.element("div");
- Class<?> type = resources.getBoundType("value");
- Type genericType = resources.getBoundGenericType("value");
- String text = String.format("description=%s,type=%s,genericType=%s", description, type.getName(), genericType.toString());
- writer.write(text);
- writer.end();
- }
+ @Inject
+ private ComponentResources resources;
+
+ @Parameter(required=true, defaultPrefix=BindingConstants.LITERAL)
+ private String description;
+
+ @Parameter(required=true)
+ private Object value;
+
+ void afterRender(MarkupWriter writer) {
+ writer.element("div");
+ Class<?> type = resources.getBoundType("value");
+ Type genericType = resources.getBoundGenericType("value");
+ String text = String.format("description=%s,type=%s,genericType=%s", description, type.getName(), genericType.toString());
+ writer.write(text);
+ writer.end();
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
index 8e9fdd3..4fdc57a 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
@@ -8,16 +8,16 @@ import java.util.Set;
import org.apache.tapestry5.annotations.Property;
public class GenericTypeDemo {
- private Set<Long> setOfLongs;
-
- @Property
- private Map<String, String> mapOfStrings;
-
- public List<List<Date>> getListOfListOfDates() {
- throw new UnsupportedOperationException();
- }
-
- public void setSetOfLongs(Set<Long> setOfLongs) {
- throw new UnsupportedOperationException();
- }
+ private Set<Long> setOfLongs;
+
+ @Property
+ private Map<String, String> mapOfStrings;
+
+ public List<List<Date>> getListOfListOfDates() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSetOfLongs(Set<Long> setOfLongs) {
+ throw new UnsupportedOperationException();
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
index 9d4a774..0aac48f 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
@@ -45,9 +45,9 @@ public class GridWithSubmitWithContextDemo
{
return F.flow(library.getTracks()).sort(new Comparator<Track>(){
- @Override
+ @Override
public int compare(Track arg0, Track arg1) {
- return arg0.getId().compareTo(arg1.getId());
+ return arg0.getId().compareTo(arg1.getId());
}
});
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
index 44e9aff..5a787e9 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
@@ -1,8 +1,8 @@
package org.apache.tapestry5.integration.app2.base;
public abstract class ChildBasePage extends ParentBasePage {
- @Override
- public String getObject() {
- return "foobar";
- }
+ @Override
+ public String getObject() {
+ return "foobar";
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
index 4030128..6c18c43 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
@@ -1,5 +1,5 @@
package org.apache.tapestry5.integration.app2.base;
public abstract class ParentBasePage {
- public abstract Object getObject();
+ public abstract Object getObject();
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
index b612d1f..c8e7d48 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
@@ -9,13 +9,13 @@ public class OverrideMethodsTest extends Assert {
/** TAP5-901 */
@Test
public void override_abstract_methods() {
- PageTester tester = new PageTester(TestConstants.APP2_PACKAGE, TestConstants.APP2_NAME);
- try {
- Document doc = tester.renderPage("OverrideAbstractMethods");
- assertEquals("6", doc.getElementById("length").getChildMarkup());
- } finally {
- tester.shutdown();
- }
+ PageTester tester = new PageTester(TestConstants.APP2_PACKAGE, TestConstants.APP2_NAME);
+ try {
+ Document doc = tester.renderPage("OverrideAbstractMethods");
+ assertEquals("6", doc.getElementById("length").getChildMarkup());
+ } finally {
+ tester.shutdown();
+ }
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
index af25c62..a861883 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
@@ -167,15 +167,15 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase
}
static class GenericBean {
- public List<Date> dates;
- public List<GenericBean> genericBeans;
-
- public List<Long> getLongs() {
- return Collections.emptyList();
- }
-
- public void setMap(Map<String, Integer> map) {
- }
+ public List<Date> dates;
+ public List<GenericBean> genericBeans;
+
+ public List<Long> getLongs() {
+ return Collections.emptyList();
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ }
}
@Test
@@ -884,15 +884,15 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase
// example from Howard
try {
- assertConduitPropertyType(Foo.class, "bar", Bar.class);
+ assertConduitPropertyType(Foo.class, "bar", Bar.class);
} catch (AssertionError e) {
- List<Method> matches = CollectionFactory.newList();
- for (Method method : Foo.class.getMethods()) {
- if (method.getName().equals("getBar")) {
- matches.add(method);
- }
- }
- fail(String.format("%s (possible candidates %s)", e.getMessage(), matches));
+ List<Method> matches = CollectionFactory.newList();
+ for (Method method : Foo.class.getMethods()) {
+ if (method.getName().equals("getBar")) {
+ matches.add(method);
+ }
+ }
+ fail(String.format("%s (possible candidates %s)", e.getMessage(), matches));
}
assertConduitPropertyType(AbstractFoo.class, "bar", AbstractBar.class);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
index 76ea531..7cb7d55 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
@@ -386,7 +386,7 @@ public final class JSONArray extends JSONCollection implements Iterable<Object>
*/
public JSONArray put(Object value)
{
- // now testValidity checks for null values.
+ // now testValidity checks for null values.
// assert value != null;
JSONObject.testValidity(value);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
index 7c5ccb4..1392bb8 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
@@ -913,7 +913,7 @@ public final class JSONObject extends JSONCollection
*/
static void printValue(JSONPrintSession session, Object value)
{
-
+
if (value instanceof JSONObject)
{
((JSONObject) value).print(session);
[05/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java b/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
new file mode 100644
index 0000000..b81c1c5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
@@ -0,0 +1,108 @@
+// 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.ioc;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Locale;
+
+/**
+ * Represents a resource on the server that may be used for server side processing, or may be exposed to the client
+ * side. Generally, this represents an abstraction on top of files on the class path and files stored in the web
+ * application context.
+ * <p/>
+ * Resources are often used as map keys; they should be immutable and should implement hashCode() and equals().
+ */
+public interface Resource
+{
+
+ /**
+ * Returns true if the resource exists; if a stream to the content of the file may be opened. A resource exists
+ * if {@link #toURL()} returns a non-null value. Starting in release 5.3.4, the result of this is cached.
+ * <p/>
+ * Starting in 5.4, some "virtual resources", may return true even though {@link #toURL()} returns null.
+ *
+ * @return true if the resource exists, false if it does not
+ */
+ boolean exists();
+
+
+ /**
+ * Returns true if the resource is virtual, meaning this is no underlying file. Many operations are unsupported
+ * on virtual resources, including {@link #toURL()}, {@link #forLocale(java.util.Locale)},
+ * {@link #withExtension(String)}, {@link #getFile()}, {@link #getFolder()}, {@link #getPath()}}; these
+ * operations will throw an {@link java.lang.UnsupportedOperationException}.
+ *
+ * @since 5.4
+ */
+ boolean isVirtual();
+
+ /**
+ * Opens a stream to the content of the resource, or returns null if the resource does not exist. The native
+ * input stream supplied by the resource is wrapped in a {@link java.io.BufferedInputStream}.
+ *
+ * @return an open, buffered stream to the content, if available
+ */
+ InputStream openStream() throws IOException;
+
+ /**
+ * Returns the URL for the resource, or null if it does not exist. This value is lazily computed; starting in 5.3.4, subclasses may cache
+ * the result. Starting in 5.4, some "virtual resources" may return null.
+ */
+ URL toURL();
+
+ /**
+ * Returns a localized version of the resource. May return null if no such resource exists. Starting in release
+ * 5.3.4, the result of this method is cached internally.
+ */
+ Resource forLocale(Locale locale);
+
+ /**
+ * Returns a Resource based on a relative path, relative to the folder containing the resource. Understands the "."
+ * (current folder) and ".." (parent folder) conventions, and treats multiple sequential slashes as a single slash.
+ * <p/>
+ * Virtual resources (resources fabricated at runtime) return themselves.
+ */
+ Resource forFile(String relativePath);
+
+ /**
+ * Returns a new Resource with the extension changed (or, if the resource does not have an extension, the extension
+ * is added). The new Resource may not exist (that is, {@link #toURL()} may return null.
+ *
+ * @param extension
+ * to apply to the resource, such as "html" or "properties"
+ * @return the new resource
+ */
+ Resource withExtension(String extension);
+
+ /**
+ * Returns the portion of the path up to the last forward slash; this is the directory or folder portion of the
+ * Resource.
+ */
+ String getFolder();
+
+ /**
+ * Returns the file portion of the Resource path, everything that follows the final forward slash.
+ * <p/>
+ * Starting in 5.4, certain kinds of "virtual resources" may return null here.
+ */
+ String getFile();
+
+ /**
+ * Return the path (the combination of folder and file).
+ * <p/>
+ * Starting in 5.4, certain "virtual resources", may return an arbitrary value here.
+ */
+ String getPath();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
new file mode 100644
index 0000000..716b7c6
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
@@ -0,0 +1,35 @@
+// 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.ioc.internal;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A null implementation of {@link AnnotationProvider}, used when there is not appropriate source of annotations.
+ */
+public class NullAnnotationProvider implements AnnotationProvider
+{
+ /**
+ * Always returns null.
+ */
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
new file mode 100644
index 0000000..6711b1a
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
@@ -0,0 +1,139 @@
+// Copyright 2006, 2007, 2012 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.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.util.CaseInsensitiveMap;
+import org.apache.tapestry5.ioc.util.Stack;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Static factory methods to ease the creation of new collection types (when using generics). Most of these method
+ * leverage the compiler's ability to match generic types by return value. Typical usage (with a static import):
+ * <p/>
+ * <pre>
+ * Map<Foo, Bar> map = newMap();
+ * </pre>
+ * <p/>
+ * <p/>
+ * This is a replacement for:
+ * <p/>
+ * <pre>
+ * Map<Foo, Bar> map = new HashMap<Foo, Bar>();
+ * </pre>
+ */
+public final class CollectionFactory
+{
+ /**
+ * Constructs and returns a generic {@link HashMap} instance.
+ */
+ public static <K, V> Map<K, V> newMap()
+ {
+ return new HashMap<K, V>();
+ }
+
+ /**
+ * Constructs and returns a generic {@link java.util.HashSet} instance.
+ */
+ public static <T> Set<T> newSet()
+ {
+ return new HashSet<T>();
+ }
+
+ /**
+ * Contructs a new {@link HashSet} and initializes it using the provided collection.
+ */
+ public static <T, V extends T> Set<T> newSet(Collection<V> values)
+ {
+ return new HashSet<T>(values);
+ }
+
+ public static <T, V extends T> Set<T> newSet(V... values)
+ {
+ // Was a call to newSet(), but Sun JDK can't handle that. Fucking generics.
+ return new HashSet<T>(Arrays.asList(values));
+ }
+
+ /**
+ * Constructs a new {@link java.util.HashMap} instance by copying an existing Map instance.
+ */
+ public static <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map)
+ {
+ return new HashMap<K, V>(map);
+ }
+
+ /**
+ * Constructs a new concurrent map, which is safe to access via multiple threads.
+ */
+ public static <K, V> ConcurrentMap<K, V> newConcurrentMap()
+ {
+ return new ConcurrentHashMap<K, V>();
+ }
+
+ /**
+ * Contructs and returns a new generic {@link java.util.ArrayList} instance.
+ */
+ public static <T> List<T> newList()
+ {
+ return new ArrayList<T>();
+ }
+
+ /**
+ * Creates a new, fully modifiable list from an initial set of elements.
+ */
+ public static <T, V extends T> List<T> newList(V... elements)
+ {
+ // Was call to newList(), but Sun JDK can't handle that.
+ return new ArrayList<T>(Arrays.asList(elements));
+ }
+
+ /**
+ * Useful for queues.
+ */
+ public static <T> LinkedList<T> newLinkedList()
+ {
+ return new LinkedList<T>();
+ }
+
+ /**
+ * Constructs and returns a new {@link java.util.ArrayList} as a copy of the provided collection.
+ */
+ public static <T, V extends T> List<T> newList(Collection<V> list)
+ {
+ return new ArrayList<T>(list);
+ }
+
+ /**
+ * Constructs and returns a new {@link java.util.concurrent.CopyOnWriteArrayList}.
+ */
+ public static <T> List<T> newThreadSafeList()
+ {
+ return new CopyOnWriteArrayList<T>();
+ }
+
+ public static <T> Stack<T> newStack()
+ {
+ return new Stack<T>();
+ }
+
+ public static <V> Map<String, V> newCaseInsensitiveMap()
+ {
+ return new CaseInsensitiveMap<V>();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
new file mode 100644
index 0000000..1a6dd80
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
@@ -0,0 +1,615 @@
+// Copyright 2008, 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.ioc.internal.util;
+
+import java.lang.reflect.*;
+import java.util.LinkedList;
+
+/**
+ * Static methods related to the use of JDK 1.5 generics.
+ */
+@SuppressWarnings("unchecked")
+public class GenericsUtils
+{
+ /**
+ * Analyzes the method in the context of containingClass and returns the Class that is represented by
+ * the method's generic return type. Any parameter information in the generic return type is lost. If you want
+ * to preserve the type parameters of the return type consider using
+ * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
+ *
+ * @param containingClass class which either contains or inherited the method
+ * @param method method from which to extract the return type
+ * @return the class represented by the methods generic return type, resolved based on the context .
+ * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
+ * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+ * @see #asClass(java.lang.reflect.Type)
+ */
+ public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
+ {
+ return asClass(resolve(method.getGenericReturnType(), containingClass));
+ }
+
+
+ /**
+ * Analyzes the field in the context of containingClass and returns the Class that is represented by
+ * the field's generic type. Any parameter information in the generic type is lost, if you want
+ * to preserve the type parameters of the return type consider using
+ * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
+ *
+ * @param containingClass class which either contains or inherited the field
+ * @param field field from which to extract the type
+ * @return the class represented by the field's generic type, resolved based on the containingClass.
+ * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
+ * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+ * @see #asClass(java.lang.reflect.Type)
+ */
+ public static Class extractGenericFieldType(Class containingClass, Field field)
+ {
+ return asClass(resolve(field.getGenericType(), containingClass));
+ }
+
+ /**
+ * Analyzes the method in the context of containingClass and returns the Class that is represented by
+ * the method's generic return type. Any parameter information in the generic return type is lost.
+ *
+ * @param containingType Type which is/represents the class that either contains or inherited the method
+ * @param method method from which to extract the generic return type
+ * @return the generic type represented by the methods generic return type, resolved based on the containingType.
+ * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+ */
+ public static Type extractActualType(Type containingType, Method method)
+ {
+ return resolve(method.getGenericReturnType(), containingType);
+ }
+
+ /**
+ * Analyzes the method in the context of containingClass and returns the Class that is represented by
+ * the method's generic return type. Any parameter information in the generic return type is lost.
+ *
+ * @param containingType Type which is/represents the class that either contains or inherited the field
+ * @param field field from which to extract the generic return type
+ * @return the generic type represented by the methods generic return type, resolved based on the containingType.
+ * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+ */
+ public static Type extractActualType(Type containingType, Field field)
+ {
+ return resolve(field.getGenericType(), containingType);
+ }
+
+ /**
+ * Resolves the type parameter based on the context of the containingType.
+ * <p/>
+ * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
+ * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
+ * instance (e.g. List<E>; List<Map<Long, String>>, E would be returned as a ParameterizedType with the raw
+ * type Map and type arguments Long and String.
+ * <p/>
+ *
+ * @param type
+ * the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
+ * @param containingType
+ * the type which his
+ * @return
+ * the type resolved to the best of our ability.
+ * @since 5.2.?
+ */
+ public static Type resolve(final Type type, final Type containingType)
+ {
+ // The type isn't generic. (String, Long, etc)
+ if (type instanceof Class)
+ return type;
+
+ // List<T>, List<String>, List<T extends Number>
+ if (type instanceof ParameterizedType)
+ return resolve((ParameterizedType) type, containingType);
+
+ // T[], List<String>[], List<T>[]
+ if (type instanceof GenericArrayType)
+ return resolve((GenericArrayType) type, containingType);
+
+ // List<? extends T>, List<? extends Object & Comparable & Serializable>
+ if (type instanceof WildcardType)
+ return resolve((WildcardType) type, containingType);
+
+ // T
+ if (type instanceof TypeVariable)
+ return resolve((TypeVariable) type, containingType);
+
+ // I'm leaning towards an exception here.
+ return type;
+ }
+
+
+ /**
+ * Determines if the suspected super type is assignable from the suspected sub type.
+ *
+ * @param suspectedSuperType
+ * e.g. GenericDAO<Pet, String>
+ * @param suspectedSubType
+ * e.g. PetDAO extends GenericDAO<Pet,String>
+ * @return
+ * true if (sourceType)targetClass is a valid cast
+ */
+ public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
+ {
+ final Class suspectedSuperClass = asClass(suspectedSuperType);
+ final Class suspectedSubClass = asClass(suspectedSubType);
+
+ // The raw types need to be compatible.
+ if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
+ {
+ return false;
+ }
+
+ // From this point we know that the raw types are assignable.
+ // We need to figure out what the generic parameters in the targetClass are
+ // as they pertain to the sourceType.
+
+ if (suspectedSuperType instanceof WildcardType)
+ {
+ // ? extends Number
+ // needs to match all the bounds (there will only be upper bounds or lower bounds
+ for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
+ {
+ if (!isAssignableFrom(t, suspectedSubType)) return false;
+ }
+ for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
+ {
+ if (!isAssignableFrom(suspectedSubType, t)) return false;
+ }
+ return true;
+ }
+
+ Type curType = suspectedSubType;
+ Class curClass;
+
+ while (curType != null && !curType.equals(Object.class))
+ {
+ curClass = asClass(curType);
+
+ if (curClass.equals(suspectedSuperClass))
+ {
+ final Type resolved = resolve(curType, suspectedSubType);
+
+ if (suspectedSuperType instanceof Class)
+ {
+ if ( resolved instanceof Class )
+ return suspectedSuperType.equals(resolved);
+
+ // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
+ // types default to Object so they must be a match.
+ // e.g. Pair p = new StringLongPair();
+ // Pair p = new Pair<? extends Number, String>
+
+ return true;
+ }
+
+ if (suspectedSuperType instanceof ParameterizedType)
+ {
+ if (resolved instanceof ParameterizedType)
+ {
+ final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
+ final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
+ if (type1Arguments.length != type2Arguments.length) return false;
+
+ for (int i = 0; i < type1Arguments.length; ++i)
+ {
+ if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
+ }
+ return true;
+ }
+ }
+ else if (suspectedSuperType instanceof GenericArrayType)
+ {
+ if (resolved instanceof GenericArrayType)
+ {
+ return isAssignableFrom(
+ ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
+ ((GenericArrayType) resolved).getGenericComponentType()
+ );
+ }
+ }
+
+ return false;
+ }
+
+ final Type[] types = curClass.getGenericInterfaces();
+ for (Type t : types)
+ {
+ final Type resolved = resolve(t, suspectedSubType);
+ if (isAssignableFrom(suspectedSuperType, resolved))
+ return true;
+ }
+
+ curType = curClass.getGenericSuperclass();
+ }
+ return false;
+ }
+
+ /**
+ * Get the class represented by the reflected type.
+ * This method is lossy; You cannot recover the type information from the class that is returned.
+ * <p/>
+ * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
+ * is lost.
+ * <p/>
+ * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
+ * then {@code Object} is returned.
+ *
+ * @param actualType
+ * a Class, ParameterizedType, GenericArrayType
+ * @return the un-parameterized class associated with the type.
+ */
+ public static Class asClass(Type actualType)
+ {
+ if (actualType instanceof Class) return (Class) actualType;
+
+ if (actualType instanceof ParameterizedType)
+ {
+ final Type rawType = ((ParameterizedType) actualType).getRawType();
+ // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
+ // some other Type. We'll assume it's a Class.
+ // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
+ return (Class) rawType;
+ }
+
+ if (actualType instanceof GenericArrayType)
+ {
+ final Type type = ((GenericArrayType) actualType).getGenericComponentType();
+ return Array.newInstance(asClass(type), 0).getClass();
+ }
+
+ if (actualType instanceof TypeVariable)
+ {
+ // Support for List<T extends Number>
+ // There is always at least one bound. If no bound is specified in the source then it will be Object.class
+ return asClass(((TypeVariable) actualType).getBounds()[0]);
+ }
+
+ if (actualType instanceof WildcardType)
+ {
+ final WildcardType wildcardType = (WildcardType) actualType;
+ final Type[] bounds = wildcardType.getLowerBounds();
+ if (bounds != null && bounds.length > 0)
+ {
+ return asClass(bounds[0]);
+ }
+ // If there is no lower bounds then the only thing that makes sense is Object.
+ return Object.class;
+ }
+
+ throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
+ }
+
+ /**
+ * Convert the type into a string. The string representation approximates the code that would be used to define the
+ * type.
+ *
+ * @param type - the type.
+ * @return a string representation of the type, similar to how it was declared.
+ */
+ public static String toString(Type type)
+ {
+ if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
+ if ( type instanceof WildcardType ) return toString((WildcardType)type);
+ if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
+ if ( type instanceof Class )
+ {
+ final Class theClass = (Class) type;
+ return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
+ }
+ return type.toString();
+ }
+
+ /**
+ * Method to resolve a TypeVariable to its most
+ * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
+ * <p/>
+ * <p/>
+ * How to resolve a TypeVariable:<br/>
+ * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
+ * given may or may not be reifiable; it may be another TypeVariable for instance.
+ * <p/>
+ * Consider <br/>
+ * <i>class Pair>A,B> { A getA(){...}; ...}</i><br/>
+ * <i>class StringLongPair extends Pair>String, Long> { }</i><br/>
+ * <p/>
+ * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
+ * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
+ * <p/>
+ * To get to the Type provided by StringLongPair you access the generics information by calling
+ * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
+ * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
+ * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
+ * <p/>
+ * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
+ * the class. When a class implements a generic interface it must provide types for the interface and any generic
+ * methods implemented from the interface will be re-defined by the class with its generic type variables.
+ *
+ * @param typeVariable - the type variable to resolve.
+ * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
+ * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
+ * declaration and the containingType.
+ */
+ private static Type resolve(TypeVariable typeVariable, Type containingType)
+ {
+ // The generic declaration is either a Class, Method or Constructor
+ final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
+
+ if (!(genericDeclaration instanceof Class))
+ {
+ // It's a method or constructor. The best we can do here is try to resolve the bounds
+ // e.g. <T extends E> T getT(T param){} where E is defined by the class.
+ final Type bounds0 = typeVariable.getBounds()[0];
+ return resolve(bounds0, containingType);
+ }
+
+ final Class typeVariableOwner = (Class) genericDeclaration;
+
+ // find the typeOwner in the containingType's hierarchy
+ final LinkedList<Type> stack = new LinkedList<Type>();
+
+ // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
+ // containingType and not the super class.
+ if (containingType instanceof ParameterizedType)
+ {
+ stack.add(containingType);
+ }
+
+ Class theClass = asClass(containingType);
+ Type genericSuperclass = theClass.getGenericSuperclass();
+ while (genericSuperclass != null && // true for interfaces with no superclass
+ !theClass.equals(Object.class) &&
+ !theClass.equals(typeVariableOwner))
+ {
+ stack.addFirst(genericSuperclass);
+ theClass = asClass(genericSuperclass);
+ genericSuperclass = theClass.getGenericSuperclass();
+ }
+
+ int i = getTypeVariableIndex(typeVariable);
+ Type resolved = typeVariable;
+ for (Type t : stack)
+ {
+ if (t instanceof ParameterizedType)
+ {
+ resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
+ if (resolved instanceof Class) return resolved;
+ if (resolved instanceof TypeVariable)
+ {
+ // Need to look at the next class in the hierarchy
+ i = getTypeVariableIndex((TypeVariable) resolved);
+ continue;
+ }
+ return resolve(resolved, containingType);
+ }
+ }
+
+ // the only way we get here is if resolved is still a TypeVariable, otherwise an
+ // exception is thrown or a value is returned.
+ return ((TypeVariable) resolved).getBounds()[0];
+ }
+
+ /**
+ * @param type - something like List<T>[] or List<? extends T>[] or T[]
+ * @param containingType - the shallowest type in the hierarchy where type is defined.
+ * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
+ */
+ private static GenericArrayType resolve(GenericArrayType type, Type containingType)
+ {
+ final Type componentType = type.getGenericComponentType();
+
+ if (!(componentType instanceof Class))
+ {
+ final Type resolved = resolve(componentType, containingType);
+ return create(resolved);
+ }
+
+ return type;
+ }
+
+ /**
+ * @param type - something like List<T>, List<T extends Number>
+ * @param containingType - the shallowest type in the hierarchy where type is defined.
+ * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
+ */
+ private static ParameterizedType resolve(ParameterizedType type, Type containingType)
+ {
+ // Use a copy because we're going to modify it.
+ final Type[] types = type.getActualTypeArguments().clone();
+
+ boolean modified = resolve(types, containingType);
+ return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
+ }
+
+ /**
+ * @param type - something like List<? super T>, List<<? extends T>, List<? extends T & Comparable<? super T>>
+ * @param containingType - the shallowest type in the hierarchy where type is defined.
+ * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
+ */
+ private static WildcardType resolve(WildcardType type, Type containingType)
+ {
+ // Use a copy because we're going to modify them.
+ final Type[] upper = type.getUpperBounds().clone();
+ final Type[] lower = type.getLowerBounds().clone();
+
+ boolean modified = resolve(upper, containingType);
+ modified = modified || resolve(lower, containingType);
+
+ return modified ? create(upper, lower) : type;
+ }
+
+ /**
+ * @param types - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
+ * @param containingType - the shallowest type in the hierarchy where type is defined.
+ * @return true if any of the types were resolved.
+ */
+ private static boolean resolve(Type[] types, Type containingType)
+ {
+ boolean modified = false;
+ for (int i = 0; i < types.length; ++i)
+ {
+ Type t = types[i];
+ if (!(t instanceof Class))
+ {
+ modified = true;
+ final Type resolved = resolve(t, containingType);
+ if (!resolved.equals(t))
+ {
+ types[i] = resolved;
+ modified = true;
+ }
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * @param rawType - the un-parameterized type.
+ * @param ownerType - the outer class or null if the class is not defined within another class.
+ * @param typeArguments - type arguments.
+ * @return a copy of the type with the typeArguments replaced.
+ */
+ static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
+ {
+ return new ParameterizedType()
+ {
+ @Override
+ public Type[] getActualTypeArguments()
+ {
+ return typeArguments;
+ }
+
+ @Override
+ public Type getRawType()
+ {
+ return rawType;
+ }
+
+ @Override
+ public Type getOwnerType()
+ {
+ return ownerType;
+ }
+
+ @Override
+ public String toString()
+ {
+ return GenericsUtils.toString(this);
+ }
+ };
+ }
+
+ static GenericArrayType create(final Type componentType)
+ {
+ return new GenericArrayType()
+ {
+ @Override
+ public Type getGenericComponentType()
+ {
+ return componentType;
+ }
+
+ @Override
+ public String toString()
+ {
+ return GenericsUtils.toString(this);
+ }
+ };
+ }
+
+ /**
+ * @param upperBounds - e.g. ? extends Number
+ * @param lowerBounds - e.g. ? super Long
+ * @return An new copy of the type with the upper and lower bounds replaced.
+ */
+ static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
+ {
+
+ return new WildcardType()
+ {
+ @Override
+ public Type[] getUpperBounds()
+ {
+ return upperBounds;
+ }
+
+ @Override
+ public Type[] getLowerBounds()
+ {
+ return lowerBounds;
+ }
+
+ @Override
+ public String toString()
+ {
+ return GenericsUtils.toString(this);
+ }
+ };
+ }
+
+ static String toString(ParameterizedType pt)
+ {
+ String s = toString(pt.getActualTypeArguments());
+ return String.format("%s<%s>", toString(pt.getRawType()), s);
+ }
+
+ static String toString(GenericArrayType gat)
+ {
+ return String.format("%s[]", toString(gat.getGenericComponentType()));
+ }
+
+ static String toString(WildcardType wt)
+ {
+ final boolean isSuper = wt.getLowerBounds().length > 0;
+ return String.format("? %s %s",
+ isSuper ? "super" : "extends",
+ isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
+ }
+
+ static String toString(Type[] types)
+ {
+ StringBuilder sb = new StringBuilder();
+ for ( Type t : types )
+ {
+ sb.append(toString(t)).append(", ");
+ }
+ return sb.substring(0, sb.length() - 2);// drop last ,
+ }
+
+ /**
+ * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
+ * the actual type.
+ *
+ * @param typeVariable - the type variable in question.
+ * @return the index of the type variable in its declaring class/method/constructor's type parameters.
+ */
+ private static int getTypeVariableIndex(final TypeVariable typeVariable)
+ {
+ // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
+ final String typeVarName = typeVariable.getName();
+ final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
+ for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
+ {
+ // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
+ if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
+ return typeArgumentIndex;
+ }
+
+ // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
+ throw new RuntimeException(
+ String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
new file mode 100644
index 0000000..ef217cb
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -0,0 +1,75 @@
+// Copyright 2006 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.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+
+/**
+ * Exception class used as a replacement for {@link java.lang.RuntimeException} when the exception is related to a
+ * particular location.
+ */
+public class TapestryException extends RuntimeException implements Locatable
+{
+ private static final long serialVersionUID = 6396903640977182682L;
+
+ private transient final Location location;
+
+ /**
+ * @param message a message (may be null)
+ * @param location implements {@link Location} or {@link Locatable}
+ * @param cause if not null, the root cause of the exception
+ */
+ public TapestryException(String message, Object location, Throwable cause)
+ {
+ this(message, InternalUtils.locationOf(location), cause);
+ }
+
+ /**
+ * @param message a message (may be null)
+ * @param cause if not null, the root cause of the exception, also used to set the location
+ */
+ public TapestryException(String message, Throwable cause)
+ {
+ this(message, cause, cause);
+ }
+
+ /**
+ * @param message a message (may be null)
+ * @param location location to associated with the exception, or null if not known
+ * @param cause if not null, the root cause of the exception
+ */
+ public TapestryException(String message, Location location, Throwable cause)
+ {
+ super(message, cause);
+
+ this.location = location;
+ }
+
+ @Override
+ public Location getLocation()
+ {
+ return location;
+ }
+
+ @Override
+ public String toString()
+ {
+ if (location == null) return super.toString();
+
+ return String.format("%s [at %s]", super.toString(), location);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
new file mode 100644
index 0000000..6159ed3
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
@@ -0,0 +1,79 @@
+// Copyright 2006, 2007, 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.ioc.services;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+/**
+ * Organizes all {@link org.apache.tapestry5.ioc.services.PropertyAdapter}s for a particular class.
+ * <p/>
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p/>
+ * When accessing properties by name, the case of the name is ignored.
+ */
+public interface ClassPropertyAdapter
+{
+ /**
+ * Returns the names of all properties, sorted into alphabetic order. This includes true properties
+ * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
+ */
+ List<String> getPropertyNames();
+
+ /**
+ * Returns the type of bean this adapter provides properties for.
+ */
+ Class getBeanType();
+
+ /**
+ * Returns the property adapter with the given name, or null if no such adapter exists.
+ *
+ * @param name of the property (case is ignored)
+ */
+ PropertyAdapter getPropertyAdapter(String name);
+
+ /**
+ * Reads the value of a property.
+ *
+ * @param instance the object to read a value from
+ * @param propertyName the name of the property to read (case is ignored)
+ * @throws UnsupportedOperationException if the property is write only
+ * @throws IllegalArgumentException if property does not exist
+ */
+ Object get(Object instance, String propertyName);
+
+ /**
+ * Updates the value of a property.
+ *
+ * @param instance the object to update
+ * @param propertyName the name of the property to update (case is ignored)
+ * @throws UnsupportedOperationException if the property is read only
+ * @throws IllegalArgumentException if property does not exist
+ */
+ void set(Object instance, String propertyName, Object value);
+
+ /**
+ * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
+ *
+ * @param instance the object to read a value from
+ * @param propertyName the name of the property to read (case is ignored)
+ * @param annotationClass the type of annotation to return
+ *
+ * @throws IllegalArgumentException if property does not exist
+ *
+ * @since 5.4
+ */
+ Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
new file mode 100644
index 0000000..b7a4cc8
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
@@ -0,0 +1,31 @@
+// Copyright 2006 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.ioc.services;
+
+/**
+ * Responsible for converting from one type to another. This is used primarily around component parameters.
+ *
+ * @param <S> the source type (input)
+ * @param <T> the target type (output)
+ */
+public interface Coercion<S, T>
+{
+ /**
+ * Converts an input value.
+ *
+ * @param input the input value
+ */
+ T coerce(S input);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
new file mode 100644
index 0000000..746de1e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
@@ -0,0 +1,145 @@
+// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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.ioc.services;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+/**
+ * An immutable object that represents a mapping from one type to another. This is also the contribution type when
+ * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
+ * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
+ * describe
+ * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
+ * coercions).
+ *
+ * @param <S>
+ * source (input) type
+ * @param <T>
+ * target (output) type
+ */
+public final class CoercionTuple<S, T>
+{
+ private final Class<S> sourceType;
+
+ private final Class<T> targetType;
+
+ private final Coercion<S, T> coercion;
+
+ /**
+ * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
+ */
+ private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
+ {
+ private final Coercion<WS, WT> coercion;
+
+ public CoercionWrapper(Coercion<WS, WT> coercion)
+ {
+ this.coercion = coercion;
+ }
+
+ @Override
+ public WT coerce(WS input)
+ {
+ return coercion.coerce(input);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s --> %s", convert(sourceType), convert(targetType));
+ }
+ }
+
+ private String convert(Class type)
+ {
+ if (Void.class.equals(type))
+ return "null";
+
+ String name = PlasticUtils.toTypeName(type);
+
+ int dotx = name.lastIndexOf('.');
+
+ // Strip off a package name of "java.lang"
+
+ if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
+ return name.substring(dotx + 1);
+
+ return name;
+ }
+
+ /**
+ * Standard constructor, which defaults wrap to true.
+ */
+ public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
+ {
+ this(sourceType, targetType, coercion, true);
+ }
+
+ /**
+ * Convenience constructor to help with generics.
+ *
+ * @since 5.2.0
+ */
+ public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
+ {
+ return new CoercionTuple<S, T>(sourceType, targetType, coercion);
+ }
+
+ /**
+ * Internal-use constructor.
+ *
+ * @param sourceType
+ * the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
+ * @param targetType
+ * the target (or output) type of the coercion
+ * @param coercion
+ * the object that performs the coercion
+ * @param wrap
+ * if true, the coercion is wrapped to provide a useful toString()
+ */
+ @SuppressWarnings("unchecked")
+ public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
+ {
+ assert sourceType != null;
+ assert targetType != null;
+ assert coercion != null;
+
+ this.sourceType = PlasticUtils.toWrapperType(sourceType);
+ this.targetType = PlasticUtils.toWrapperType(targetType);
+ this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
+ }
+
+ @Override
+ public String toString()
+ {
+ return coercion.toString();
+ }
+
+ public Coercion<S, T> getCoercion()
+ {
+ return coercion;
+ }
+
+ public Class<S> getSourceType()
+ {
+ return sourceType;
+ }
+
+ public Class<T> getTargetType()
+ {
+ return targetType;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
new file mode 100644
index 0000000..ae542c5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
@@ -0,0 +1,77 @@
+// Copyright 2006, 2010, 2013 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.ioc.services;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
+ * <p/>
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p>
+ * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
+ * is a name conflict, the true property will be favored over the field access.
+ */
+public interface PropertyAccess
+{
+ /**
+ * Reads the value of a property.
+ *
+ * @throws UnsupportedOperationException
+ * if the property is write only
+ * @throws IllegalArgumentException
+ * if property does not exist
+ */
+ Object get(Object instance, String propertyName);
+
+ /**
+ * Updates the value of a property.
+ *
+ * @throws UnsupportedOperationException
+ * if the property is read only
+ * @throws IllegalArgumentException
+ * if property does not exist
+ */
+ void set(Object instance, String propertyName, Object value);
+
+ /**
+ * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
+ * A convenience over invoking {@link #getAdapter(Object)}.{@link ClassPropertyAdapter#getPropertyAdapter(String)}.{@link PropertyAdapter#getAnnotation(Class)}
+ *
+ * @param instance the object to read a value from
+ * @param propertyName the name of the property to read (case is ignored)
+ * @param annotationClass the type of annotation to return
+ * @throws IllegalArgumentException
+ * if property does not exist
+ *
+ * @since 5.4
+ */
+ Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
+
+ /**
+ * Returns the adapter for a particular object instance. A convienience over invoking {@link #getAdapter(Class)}.
+ */
+ ClassPropertyAdapter getAdapter(Object instance);
+
+ /**
+ * Returns the adapter used to access properties within the indicated class.
+ */
+ ClassPropertyAdapter getAdapter(Class forClass);
+
+ /**
+ * Discards all stored property access information, discarding all created class adapters.
+ */
+ void clearCache();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
new file mode 100644
index 0000000..947535e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
@@ -0,0 +1,121 @@
+// Copyright 2006, 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.ioc.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
+ * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
+ * by the underlying field (when the property name matches the field name).
+ * <p/>
+ * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
+ *
+ * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
+ */
+@SuppressWarnings("unchecked")
+public interface PropertyAdapter extends AnnotationProvider
+{
+ /**
+ * Returns the name of the property (or public field).
+ */
+ String getName();
+
+ /**
+ * Returns true if the property is readable (i.e., has a getter method or is a public field).
+ */
+ boolean isRead();
+
+ /**
+ * Returns the method used to read the property, or null if the property is not readable (or is a public field).
+ */
+ public Method getReadMethod();
+
+ /**
+ * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
+ */
+ boolean isUpdate();
+
+ /**
+ * Returns the method used to update the property, or null if the property is not writeable (or a public field).
+ */
+ public Method getWriteMethod();
+
+ /**
+ * Reads the property value.
+ *
+ * @param instance to read from
+ * @throws UnsupportedOperationException if the property is write only
+ */
+ Object get(Object instance);
+
+ /**
+ * Updates the property value. The provided value must not be null if the property type is primitive, and must
+ * otherwise be of the proper type.
+ *
+ * @param instance to update
+ * @param value new value for the property
+ * @throws UnsupportedOperationException if the property is read only
+ */
+ void set(Object instance, Object value);
+
+ /**
+ * Returns the type of the property.
+ */
+ Class getType();
+
+ /**
+ * Returns true if the return type of the read method is not the same as the property type. This can occur when the
+ * property has been defined using generics, in which case, the method's type may be Object when the property type
+ * is something more specific. This method is primarily used when generating runtime code related to the property.
+ */
+ boolean isCastRequired();
+
+ /**
+ * Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
+ * properties defined by the same class.
+ */
+ ClassPropertyAdapter getClassAdapter();
+
+ /**
+ * Returns the type of bean to which this property belongs. This is the same as
+ * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
+ */
+ Class getBeanType();
+
+ /**
+ * Returns true if the property is actually a public field (possibly, a public static field).
+ *
+ * @since 5.2
+ */
+ boolean isField();
+
+ /**
+ * Returns the field if the property is a public field or null if the property is accessed via the read method.
+ *
+ * @since 5.2
+ */
+ Field getField();
+
+ /**
+ * The class in which the property (or public field) is defined.
+ *
+ * @since 5.2
+ */
+ Class getDeclaringClass();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
new file mode 100644
index 0000000..ec8eaad
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
@@ -0,0 +1,88 @@
+// Copyright 2006, 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.ioc.services;
+
+import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
+
+/**
+ * Makes use of {@link org.apache.tapestry5.ioc.services.Coercion}s to convert between an input value (of some specific
+ * type) and a desired output type. Smart about coercing, even if it requires multiple coercion steps (i.e., via an
+ * intermediate type, such as String).
+ */
+@UsesConfiguration(CoercionTuple.class)
+public interface TypeCoercer
+{
+ /**
+ * Performs a coercion from an input type to a desired output type. When the target type is a primitive, the actual
+ * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
+ * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
+ * the search are cached.
+ * <p/>
+ * The TypeCoercer also caches the results of a coercion search.
+ *
+ * @param <S>
+ * source type (input)
+ * @param <T>
+ * target type (output)
+ * @param input
+ * @param targetType
+ * defines the target type
+ * @return the coerced value
+ * @throws RuntimeException
+ * if the input can not be coerced
+ */
+ <S, T> T coerce(S input, Class<T> targetType);
+
+ /**
+ * Given a source and target type, computes the coercion that will be used.
+ * <p>
+ * Note: holding the returned coercion past the time when {@linkplain #clearCache() the cache is cleared} can cause
+ * a memory leak, especially in the context of live reloading (wherein holding a reference to a single class make
+ * keep an entire ClassLoader from being reclaimed).
+ *
+ * @since 5.2.0
+ * @param <S>
+ * source type (input)
+ * @param <T>
+ * target type (output)
+ * @param sourceType
+ * type to coerce from
+ * @param targetType
+ * defines the target type
+ * @return the coercion that will ultimately be used
+ */
+ <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType);
+
+ /**
+ * Used primarily inside test suites, this method performs the same steps as {@link #coerce(Object, Class)}, but
+ * returns a string describing the series of coercions, such as "Object --> String --> Long --> Integer".
+ *
+ * @param <S>
+ * source type (input)
+ * @param <T>
+ * target type (output)
+ * @param sourceType
+ * the source coercion type (use void.class for coercions from null)
+ * @param targetType
+ * defines the target type
+ * @return a string identifying the series of coercions, or the empty string if no coercion is necessary
+ */
+ <S, T> String explain(Class<S> sourceType, Class<T> targetType);
+
+ /**
+ * Clears cached information stored by the TypeCoercer.
+ */
+ void clearCache();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
new file mode 100644
index 0000000..c4c5c6d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -0,0 +1,87 @@
+// 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.ioc.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+
+/**
+ * Used (as part of a {@link UnknownValueException} to identify what available values
+ * are present.
+ *
+ * @since 5.2.0
+ */
+public class AvailableValues
+{
+ private final String valueType;
+
+ private final List<String> values;
+
+ /**
+ * @param valueType
+ * a word or phrase that describes what the values are such as "component types" or "service ids"
+ *@param values
+ * a set of objects defining the values; the values will be converted to strings and sorted into
+ * ascending order
+ */
+ public AvailableValues(String valueType, Collection<?> values)
+ {
+ this.valueType = valueType;
+ this.values = sortValues(values);
+ }
+
+ public AvailableValues(String valueType, Map<?, ?> map)
+ {
+ this(valueType, map.keySet());
+ }
+
+ private static List<String> sortValues(Collection<?> values)
+ {
+ List<String> result = CollectionFactory.newList();
+
+ for (Object v : values)
+ {
+ result.add(String.valueOf(v));
+ }
+
+ Collections.sort(result);
+
+ return Collections.unmodifiableList(result);
+ }
+
+ /** The type of value, i.e., "component types" or "service ids". */
+ public String getValueType()
+ {
+ return valueType;
+ }
+
+ /** The values, as strings, in sorted order. */
+ public List<String> getValues()
+ {
+ return values;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
new file mode 100644
index 0000000..f5aff7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
@@ -0,0 +1,499 @@
+// 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.ioc.util;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * An mapped collection where the keys are always strings and access to values is case-insensitive. The case of keys in
+ * the map is <em>maintained</em>, but on any access to a key (directly or indirectly), all key comparisons are
+ * performed in a case-insensitive manner. The map implementation is intended to support a reasonably finite number
+ * (dozens or hundreds, not thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of
+ * entries rather than hash bucket. It is also geared towards a largely static map, one that is created and then used
+ * without modification.
+ *
+ * @param <V> the type of value stored
+ */
+public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
+{
+ private static final long serialVersionUID = 3362718337611953298L;
+
+ private static final int NULL_HASH = Integer.MIN_VALUE;
+
+ private static final int DEFAULT_SIZE = 20;
+
+ private static class CIMEntry<V> implements Map.Entry<String, V>, Serializable
+ {
+ private static final long serialVersionUID = 6713986085221148350L;
+
+ private String key;
+
+ private final int hashCode;
+
+ V value;
+
+ public CIMEntry(final String key, final int hashCode, V value)
+ {
+ this.key = key;
+ this.hashCode = hashCode;
+ this.value = value;
+ }
+
+ @Override
+ public String getKey()
+ {
+ return key;
+ }
+
+ @Override
+ public V getValue()
+ {
+ return value;
+ }
+
+ @Override
+ public V setValue(V value)
+ {
+ V result = this.value;
+
+ this.value = value;
+
+ return result;
+ }
+
+ /**
+ * Returns true if both keys are null, or if the provided key is the same as, or case-insensitively equal to,
+ * the entrie's key.
+ *
+ * @param key to compare against
+ * @return true if equal
+ */
+ @SuppressWarnings({ "StringEquality" })
+ boolean matches(String key)
+ {
+ return key == this.key || (key != null && key.equalsIgnoreCase(this.key));
+ }
+
+ boolean valueMatches(Object value)
+ {
+ return value == this.value || (value != null && value.equals(this.value));
+ }
+ }
+
+ private class EntrySetIterator implements Iterator
+ {
+ int expectedModCount = modCount;
+
+ int index;
+
+ int current = -1;
+
+ @Override
+ public boolean hasNext()
+ {
+ return index < size;
+ }
+
+ @Override
+ public Object next()
+ {
+ check();
+
+ if (index >= size) throw new NoSuchElementException();
+
+ current = index++;
+
+ return entries[current];
+ }
+
+ @Override
+ public void remove()
+ {
+ check();
+
+ if (current < 0) throw new NoSuchElementException();
+
+ new Position(current, true).remove();
+
+ expectedModCount = modCount;
+ }
+
+ private void check()
+ {
+ if (expectedModCount != modCount) throw new ConcurrentModificationException();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private class EntrySet extends AbstractSet
+ {
+ @Override
+ public Iterator iterator()
+ {
+ return new EntrySetIterator();
+ }
+
+ @Override
+ public int size()
+ {
+ return size;
+ }
+
+ @Override
+ public void clear()
+ {
+ CaseInsensitiveMap.this.clear();
+ }
+
+ @Override
+ public boolean contains(Object o)
+ {
+ if (!(o instanceof Map.Entry)) return false;
+
+ Map.Entry e = (Map.Entry) o;
+
+ Position position = select(e.getKey());
+
+ return position.isFound() && position.entry().valueMatches(e.getValue());
+ }
+
+ @Override
+ public boolean remove(Object o)
+ {
+ if (!(o instanceof Map.Entry)) return false;
+
+ Map.Entry e = (Map.Entry) o;
+
+ Position position = select(e.getKey());
+
+ if (position.isFound() && position.entry().valueMatches(e.getValue()))
+ {
+ position.remove();
+ return true;
+ }
+
+ return false;
+ }
+
+ }
+
+ private class Position
+ {
+ private final int cursor;
+
+ private final boolean found;
+
+ Position(int cursor, boolean found)
+ {
+ this.cursor = cursor;
+ this.found = found;
+ }
+
+ boolean isFound()
+ {
+ return found;
+ }
+
+ CIMEntry<V> entry()
+ {
+ return entries[cursor];
+ }
+
+ V get()
+ {
+ return found ? entries[cursor].value : null;
+ }
+
+ V remove()
+ {
+ if (!found) return null;
+
+ V result = entries[cursor].value;
+
+ // Remove the entry by shifting everything else down.
+
+ System.arraycopy(entries, cursor + 1, entries, cursor, size - cursor - 1);
+
+ // We shifted down, leaving one (now duplicate) entry behind.
+
+ entries[--size] = null;
+
+ // A structural change for sure
+
+ modCount++;
+
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ V put(String key, int hashCode, V newValue)
+ {
+ if (found)
+ {
+ CIMEntry<V> e = entries[cursor];
+
+ V result = e.value;
+
+ // Not a structural change, so no change to modCount
+
+ // Update the key (to maintain case). By definition, the hash code
+ // will not change.
+
+ e.key = key;
+ e.value = newValue;
+
+ return result;
+ }
+
+ // Not found, we're going to add it.
+
+ int newSize = size + 1;
+
+ if (newSize == entries.length)
+ {
+ // Time to expand!
+
+ int newCapacity = (size * 3) / 2 + 1;
+
+ CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
+
+ System.arraycopy(entries, 0, newEntries, 0, cursor);
+
+ System.arraycopy(entries, cursor, newEntries, cursor + 1, size - cursor);
+
+ entries = newEntries;
+ }
+ else
+ {
+ // Open up a space for the new entry
+
+ System.arraycopy(entries, cursor, entries, cursor + 1, size - cursor);
+ }
+
+ CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, newValue);
+ entries[cursor] = newEntry;
+
+ size++;
+
+ // This is definately a structural change
+
+ modCount++;
+
+ return null;
+ }
+
+ }
+
+ // The list of entries. This is kept sorted by hash code. In some cases, there may be different
+ // keys with the same hash code in adjacent indexes.
+ private CIMEntry<V>[] entries;
+
+ private int size = 0;
+
+ // Used by iterators to check for concurrent modifications
+
+ private transient int modCount = 0;
+
+ private transient Set<Map.Entry<String, V>> entrySet;
+
+ public CaseInsensitiveMap()
+ {
+ this(DEFAULT_SIZE);
+ }
+
+ @SuppressWarnings("unchecked")
+ public CaseInsensitiveMap(int size)
+ {
+ entries = new CIMEntry[Math.max(size, 3)];
+ }
+
+ public CaseInsensitiveMap(Map<String, ? extends V> map)
+ {
+ this(map.size());
+
+ for (Map.Entry<String, ? extends V> entry : map.entrySet())
+ {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ @Override
+ public void clear()
+ {
+ for (int i = 0; i < size; i++)
+ entries[i] = null;
+
+ size = 0;
+ modCount++;
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return size == 0;
+ }
+
+ @Override
+ public int size()
+ {
+ return size;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public V put(String key, V value)
+ {
+ int hashCode = caseInsenitiveHashCode(key);
+
+ return select(key, hashCode).put(key, hashCode, value);
+ }
+
+ @Override
+ public boolean containsKey(Object key)
+ {
+ return select(key).isFound();
+ }
+
+ @Override
+ public V get(Object key)
+ {
+ return select(key).get();
+ }
+
+ @Override
+ public V remove(Object key)
+ {
+ return select(key).remove();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Set<Map.Entry<String, V>> entrySet()
+ {
+ if (entrySet == null) entrySet = new EntrySet();
+
+ return entrySet;
+ }
+
+ private Position select(Object key)
+ {
+ if (key == null || key instanceof String)
+ {
+ String keyString = (String) key;
+ return select(keyString, caseInsenitiveHashCode(keyString));
+ }
+
+ return new Position(0, false);
+ }
+
+ /**
+ * Searches the elements for the index of the indicated key and (case insensitive) hash code. Sets the _cursor and
+ * _found attributes.
+ */
+ private Position select(String key, int hashCode)
+ {
+ if (size == 0) return new Position(0, false);
+
+ int low = 0;
+ int high = size - 1;
+
+ int cursor;
+
+ while (low <= high)
+ {
+ cursor = (low + high) >> 1;
+
+ CIMEntry e = entries[cursor];
+
+ if (e.hashCode < hashCode)
+ {
+ low = cursor + 1;
+ continue;
+ }
+
+ if (e.hashCode > hashCode)
+ {
+ high = cursor - 1;
+ continue;
+ }
+
+ return tunePosition(key, hashCode, cursor);
+ }
+
+ return new Position(low, false);
+ }
+
+ /**
+ * select() has located a matching hashCode, but there's an outlying possibility that multiple keys share the same
+ * hashCode. Backup the cursor until we get to locate the initial hashCode match, then march forward until the key
+ * is located, or the hashCode stops matching.
+ *
+ * @param key
+ * @param hashCode
+ */
+ private Position tunePosition(String key, int hashCode, int cursor)
+ {
+ boolean found = false;
+
+ while (cursor > 0)
+ {
+ if (entries[cursor - 1].hashCode != hashCode) break;
+
+ cursor--;
+ }
+
+ while (true)
+ {
+ if (entries[cursor].matches(key))
+ {
+ found = true;
+ break;
+ }
+
+ // Advance to the next entry.
+
+ cursor++;
+
+ // If out of entries,
+ if (cursor >= size || entries[cursor].hashCode != hashCode) break;
+ }
+
+ return new Position(cursor, found);
+ }
+
+ static int caseInsenitiveHashCode(String input)
+ {
+ if (input == null) return NULL_HASH;
+
+ int length = input.length();
+ int hash = 0;
+
+ // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
+ // changes its implementation. Let's hope this is reasonably fast.
+
+ for (int i = 0; i < length; i++)
+ {
+ int ch = input.charAt(i);
+
+ int caselessCh = Character.toLowerCase(ch);
+
+ hash = 31 * hash + caselessCh;
+ }
+
+ return hash;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
new file mode 100644
index 0000000..2feaeca
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
@@ -0,0 +1,115 @@
+// Copyright 2008-2013 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.ioc.util;
+
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+
+/**
+ * Contains static methods useful for manipulating exceptions.
+ */
+public class ExceptionUtils
+{
+ /**
+ * Locates a particular type of exception, working its way via the cause property of each exception in the exception
+ * stack.
+ *
+ * @param t the outermost exception
+ * @param type the type of exception to search for
+ * @return the first exception of the given type, if found, or null
+ */
+ public static <T extends Throwable> T findCause(Throwable t, Class<T> type)
+ {
+ Throwable current = t;
+
+ while (current != null)
+ {
+ if (type.isInstance(current))
+ {
+ return type.cast(current);
+ }
+
+ // Not a match, work down.
+
+ current = current.getCause();
+ }
+
+ return null;
+ }
+
+ /**
+ * Locates a particular type of exception, working its way down via any property that returns some type of Exception.
+ * This is more expensive, but more accurate, than {@link #findCause(Throwable, Class)} as it works with older exceptions
+ * that do not properly implement the (relatively new) {@linkplain Throwable#getCause() cause property}.
+ *
+ * @param t the outermost exception
+ * @param type the type of exception to search for
+ * @param access used to access properties
+ * @return the first exception of the given type, if found, or null
+ */
+ public static <T extends Throwable> T findCause(Throwable t, Class<T> type, PropertyAccess access)
+ {
+ Throwable current = t;
+
+ while (current != null)
+ {
+ if (type.isInstance(current))
+ {
+ return type.cast(current);
+ }
+
+ Throwable next = null;
+
+ ClassPropertyAdapter adapter = access.getAdapter(current);
+
+ for (String name : adapter.getPropertyNames())
+ {
+
+ Object value = adapter.getPropertyAdapter(name).get(current);
+
+ if (value != null && value != current && value instanceof Throwable)
+ {
+ next = (Throwable) value;
+ break;
+ }
+ }
+
+ current = next;
+ }
+
+
+ return null;
+ }
+
+ /**
+ * Extracts the message from an exception. If the exception's message is null, returns the exceptions class name.
+ *
+ * @param exception
+ * to extract message from
+ * @return message or class name
+ * @since 5.4
+ */
+ public static String toMessage(Throwable exception)
+ {
+ assert exception != null;
+
+ String message = exception.getMessage();
+
+ if (message != null)
+ return message;
+
+ return exception.getClass().getName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
new file mode 100644
index 0000000..470b611
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
@@ -0,0 +1,47 @@
+// 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.ioc.util;
+
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+
+/**
+ * Special exception used when a value (typically from a map) is referenced that does not exist. Uses a
+ * {@link AvailableValues} object
+ * to track what the known values are.
+ *
+ * @since 5.2.0
+ */
+public class UnknownValueException extends TapestryException
+{
+ private final AvailableValues availableValues;
+
+ public UnknownValueException(String message, AvailableValues availableValues)
+ {
+ this(message, null, null, availableValues);
+ }
+
+ public UnknownValueException(String message, Object location, Throwable cause, AvailableValues availableValues)
+ {
+ super(message, location, cause);
+
+ this.availableValues = availableValues;
+ }
+
+ public AvailableValues getAvailableValues()
+ {
+ return availableValues;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
new file mode 100644
index 0000000..77b028e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
@@ -0,0 +1,60 @@
+// Copyright 2006, 2007, 2008, 2011, 2012 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.services;
+
+import java.util.Map;
+
+/**
+ * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple
+ * event hub services implementing this interface, each with a specific marker annotation; each can register listeners
+ * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support
+ * for:
+ * <dl>
+ * <dt>message catalog resources
+ * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation
+ * <dt>component templates
+ * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation
+ * <dt>component classes
+ * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation
+ * </dl>
+ * <p/>
+ * Starting in Tapestry 5.3, these services are disabled in production (it does nothing).
+ *
+ * @since 5.1.0.0
+ */
+public interface InvalidationEventHub
+{
+ /**
+ * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the
+ * receiver may discard any cached data that may have been invalidated). Does nothing in production mode.
+ *
+ * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead}
+ */
+ void addInvalidationListener(InvalidationListener listener);
+
+ /**
+ * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode.
+ *
+ * @since 5.4
+ */
+ void addInvalidationCallback(Runnable callback);
+
+ /**
+ * Adds a callback that clears the map.
+ *
+ * @since 5.4
+ */
+ void clearOnInvalidation(Map<?,?> map);
+}
[07/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
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/f963c7ab
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/f963c7ab
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/f963c7ab
Branch: refs/heads/beanmodel-split
Commit: f963c7ab7ebaf1b4b0349c9875a5490a85d75dd0
Parents: 09a011c
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 15:16:02 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 15:16:02 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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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);
+ }
+}
[13/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
new file mode 100644
index 0000000..49b0b15
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
@@ -0,0 +1,59 @@
+// Copyright 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+/**
+ * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
+ */
+public class AnnotationProviderChain implements AnnotationProvider
+{
+ private final AnnotationProvider[] providers;
+
+ public AnnotationProviderChain(AnnotationProvider[] providers)
+ {
+ this.providers = providers;
+ }
+
+ /**
+ * Creates an AnnotationProvider from the list of providers. Returns either an {@link AnnotationProviderChain} or
+ * the sole element in the list.
+ */
+ public static AnnotationProvider create(List<AnnotationProvider> providers)
+ {
+ int size = providers.size();
+
+ if (size == 1) return providers.get(0);
+
+ return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ for (AnnotationProvider p : providers)
+ {
+ T result = p.getAnnotation(annotationClass);
+
+ if (result != null) return result;
+ }
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
new file mode 100644
index 0000000..4a5dece
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
@@ -0,0 +1,54 @@
+// Copyright 2006, 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.services.Coercion;
+
+/**
+ * Combines two coercions to create a coercion through an intermediate type.
+ *
+ * @param <S> The source (input) type
+ * @param <I> The intermediate type
+ * @param <T> The target (output) type
+ */
+public class CompoundCoercion<S, I, T> implements Coercion<S, T>
+{
+ private final Coercion<S, I> op1;
+
+ private final Coercion<I, T> op2;
+
+ public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
+ {
+ this.op1 = op1;
+ this.op2 = op2;
+ }
+
+ @Override
+ public T coerce(S input)
+ {
+ // Run the input through the first operation (S --> I), then run the result of that through
+ // the second operation (I --> T).
+
+ I intermediate = op1.coerce(input);
+
+ return op2.coerce(intermediate);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s, %s", op1, op2);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
new file mode 100644
index 0000000..e92ef2d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
@@ -0,0 +1,68 @@
+// Copyright 2006, 2007, 2011, 2012 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+public class ServiceMessages
+{
+ private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
+
+ private ServiceMessages()
+ {
+ }
+
+ public static String noSuchProperty(Class clazz, String propertyName)
+ {
+ return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
+ }
+
+
+ public static String readFailure(String propertyName, Object instance, Throwable cause)
+ {
+ return MESSAGES.format("read-failure", propertyName, instance, cause);
+ }
+
+ public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
+ Class expectedType)
+ {
+ return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
+ expectedType.getName());
+ }
+
+ public static String shutdownListenerError(Object listener, Throwable cause)
+ {
+ return MESSAGES.format("shutdown-listener-error", listener, cause);
+ }
+
+ public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
+ {
+ return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
+ coercion, cause);
+ }
+
+ public static String registryShutdown(String serviceId)
+ {
+ return MESSAGES.format("registry-shutdown", serviceId);
+ }
+
+ public static String serviceBuildFailure(String serviceId, Throwable cause)
+ {
+ return MESSAGES.format("service-build-failure", serviceId, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
new file mode 100644
index 0000000..0769b7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
@@ -0,0 +1,65 @@
+// 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Resource;
+
+/**
+ * Implementation of {@link Location} used when the underlying resource isn't really known.
+ */
+public final class StringLocation implements Location
+{
+ private final String description;
+
+ private final int line;
+
+ public StringLocation(String description, int line)
+ {
+ this.description = description;
+ this.line = line;
+ }
+
+ @Override
+ public String toString()
+ {
+ return description;
+ }
+
+ /**
+ * Returns 0.
+ */
+ @Override
+ public int getColumn()
+ {
+ return 0;
+ }
+
+ @Override
+ public int getLine()
+ {
+ return line;
+ }
+
+ /**
+ * Returns null; we don't know where the file really is (it's probably a class on the class path).
+ */
+ @Override
+ public Resource getResource()
+ {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
new file mode 100644
index 0000000..6481384
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
@@ -0,0 +1,508 @@
+// Copyright 2006, 2007, 2008, 2010, 2012 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.ioc.internal.services;
+
+import org.apache.tapestry5.func.F;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.LockSupport;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+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.util.StringToEnumCoercion;
+
+import java.util.*;
+
+@SuppressWarnings("all")
+public class TypeCoercerImpl extends LockSupport implements TypeCoercer
+{
+ // Constructed from the service's configuration.
+
+ private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
+
+ /**
+ * A coercion to a specific target type. Manages a cache of coercions to specific types.
+ */
+ private class TargetCoercion
+ {
+ private final Class type;
+
+ private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
+
+ TargetCoercion(Class type)
+ {
+ this.type = type;
+ }
+
+ void clearCache()
+ {
+ cache.clear();
+ }
+
+ Object coerce(Object input)
+ {
+ Class sourceType = input != null ? input.getClass() : Void.class;
+
+ if (type.isAssignableFrom(sourceType))
+ {
+ return input;
+ }
+
+ Coercion c = getCoercion(sourceType);
+
+ try
+ {
+ return type.cast(c.coerce(input));
+ } catch (Exception ex)
+ {
+ throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
+ }
+ }
+
+ String explain(Class sourceType)
+ {
+ return getCoercion(sourceType).toString();
+ }
+
+ private Coercion getCoercion(Class sourceType)
+ {
+ Coercion c = cache.get(sourceType);
+
+ if (c == null)
+ {
+ c = findOrCreateCoercion(sourceType, type);
+ cache.put(sourceType, c);
+ }
+
+ return c;
+ }
+ }
+
+ /**
+ * Map from a target type to a TargetCoercion for that type.
+ */
+ private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
+
+ private static final Coercion NO_COERCION = new Coercion<Object, Object>()
+ {
+ @Override
+ public Object coerce(Object input)
+ {
+ return input;
+ }
+ };
+
+ private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
+ {
+ @Override
+ public Object coerce(Void input)
+ {
+ return null;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "null --> null";
+ }
+ };
+
+ public TypeCoercerImpl(Collection<CoercionTuple> tuples)
+ {
+ for (CoercionTuple tuple : tuples)
+ {
+ Class key = tuple.getSourceType();
+
+ InternalCommonsUtils.addToMapList(sourceTypeToTuple, key, tuple);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object coerce(Object input, Class targetType)
+ {
+ assert targetType != null;
+
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+ if (effectiveTargetType.isInstance(input))
+ {
+ return input;
+ }
+
+
+ return getTargetCoercion(effectiveTargetType).coerce(input);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
+ {
+ assert sourceType != null;
+ assert targetType != null;
+
+ Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+ if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+ {
+ return NO_COERCION;
+ }
+
+ return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
+ {
+ assert sourceType != null;
+ assert targetType != null;
+
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+ Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+
+ // Is a coercion even necessary? Not if the target type is assignable from the
+ // input value.
+
+ if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+ {
+ return "";
+ }
+
+ return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
+ }
+
+ private TargetCoercion getTargetCoercion(Class targetType)
+ {
+ try
+ {
+ acquireReadLock();
+
+ TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+ return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
+ } finally
+ {
+ releaseReadLock();
+ }
+ }
+
+ private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
+ {
+ try
+ {
+ upgradeReadLockToWriteLock();
+
+ // Inner check since some other thread may have beat us to it.
+
+ TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+ if (tc == null)
+ {
+ tc = new TargetCoercion(targetType);
+ typeToTargetCoercion.put(targetType, tc);
+ }
+
+ return tc;
+ } finally
+ {
+ downgradeWriteLockToReadLock();
+ }
+ }
+
+ @Override
+ public void clearCache()
+ {
+ try
+ {
+ acquireReadLock();
+
+ // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
+ // will release the keys for classes that are no longer in existence. On the other hand,
+ // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
+ // individual cache, so clear all those.
+
+ for (TargetCoercion tc : typeToTargetCoercion.values())
+ {
+ // Can tc ever be null?
+
+ tc.clearCache();
+ }
+ } finally
+ {
+ releaseReadLock();
+ }
+ }
+
+ /**
+ * Here's the real meat; we do a search of the space to find coercions, or a system of
+ * coercions, that accomplish
+ * the desired coercion.
+ * <p/>
+ * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
+ * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
+ * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
+ * <p/>
+ * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
+ * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
+ * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
+ * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
+ * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
+ * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
+ * final response.
+ * <p/>
+ * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
+ * really good at.
+ *
+ * @param sourceType
+ * @param targetType
+ * @return coercer from sourceType to targetType
+ */
+ @SuppressWarnings("unchecked")
+ private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
+ {
+ if (sourceType == Void.class)
+ {
+ return searchForNullCoercion(targetType);
+ }
+
+ // These are instance variables because this method may be called concurrently.
+ // On a true race, we may go to the work of seeking out and/or fabricating
+ // a tuple twice, but it's more likely that different threads are looking
+ // for different source/target coercions.
+
+ Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
+ LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
+
+ seedQueue(sourceType, targetType, consideredTuples, queue);
+
+ while (!queue.isEmpty())
+ {
+ CoercionTuple tuple = queue.removeFirst();
+
+ // If the tuple results in a value type that is assignable to the desired target type,
+ // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
+ // "quality" (how close is the tuple target type to the desired target type). Cost
+ // is currently implicit, as compound tuples are stored deeper in the queue,
+ // so simpler coercions will be located earlier.
+
+ Class tupleTargetType = tuple.getTargetType();
+
+ if (targetType.isAssignableFrom(tupleTargetType))
+ {
+ return tuple.getCoercion();
+ }
+
+ // So .. this tuple doesn't get us directly to the target type.
+ // However, it *may* get us part of the way. Each of these
+ // represents a coercion from the source type to an intermediate type.
+ // Now we're going to look for conversions from the intermediate type
+ // to some other type.
+
+ queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
+ }
+
+ // Not found anywhere. Identify the source and target type and a (sorted) list of
+ // all the known coercions.
+
+ throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
+ sourceType.getName(), targetType.getName()), buildCoercionCatalog());
+ }
+
+ /**
+ * Coercion from null is special; we match based on the target type and its not a spanning
+ * search. In many cases, we
+ * return a pass-thru that leaves the value as null.
+ *
+ * @param targetType
+ * desired type
+ * @return the coercion
+ */
+ private Coercion searchForNullCoercion(Class targetType)
+ {
+ List<CoercionTuple> tuples = getTuples(Void.class, targetType);
+
+ for (CoercionTuple tuple : tuples)
+ {
+ Class tupleTargetType = tuple.getTargetType();
+
+ if (targetType.equals(tupleTargetType))
+ return tuple.getCoercion();
+ }
+
+ // Typical case: no match, this coercion passes the null through
+ // as null.
+
+ return COERCION_NULL_TO_OBJECT;
+ }
+
+ /**
+ * Builds a string listing all the coercions configured for the type coercer, sorted
+ * alphabetically.
+ */
+ @SuppressWarnings("unchecked")
+ private AvailableValues buildCoercionCatalog()
+ {
+ List<CoercionTuple> masterList = CollectionFactory.newList();
+
+ for (List<CoercionTuple> list : sourceTypeToTuple.values())
+ {
+ masterList.addAll(list);
+ }
+
+ return new AvailableValues("Configured coercions", masterList);
+ }
+
+ /**
+ * Seeds the pool with the initial set of coercions for the given type.
+ */
+ private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
+ LinkedList<CoercionTuple> queue)
+ {
+ // Work from the source type up looking for tuples
+
+ for (Class c : new InheritanceSearch(sourceType))
+ {
+ List<CoercionTuple> tuples = getTuples(c, targetType);
+
+ if (tuples == null)
+ {
+ continue;
+ }
+
+ for (CoercionTuple tuple : tuples)
+ {
+ queue.addLast(tuple);
+ consideredTuples.add(tuple);
+ }
+
+ // Don't pull in Object -> type coercions when doing
+ // a search from null.
+
+ if (sourceType == Void.class)
+ {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
+ * compound coercion tuples
+ * to the end of the queue.
+ *
+ * @param sourceType
+ * the source type of the coercion
+ * @param targetType
+ * TODO
+ * @param intermediateTuple
+ * a tuple that converts from the source type to some intermediate type (that is not
+ * assignable to the target type)
+ * @param consideredTuples
+ * set of tuples that have already been added to the pool (directly, or as a compound
+ * coercion)
+ * @param queue
+ * the work queue of tuples
+ */
+ @SuppressWarnings("unchecked")
+ private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
+ Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
+ {
+ Class intermediateType = intermediateTuple.getTargetType();
+
+ for (Class c : new InheritanceSearch(intermediateType))
+ {
+ for (CoercionTuple tuple : getTuples(c, targetType))
+ {
+ if (consideredTuples.contains(tuple))
+ {
+ continue;
+ }
+
+ Class newIntermediateType = tuple.getTargetType();
+
+ // If this tuple is for coercing from an intermediate type back towards our
+ // initial source type, then ignore it. This should only be an optimization,
+ // as branches that loop back towards the source type will
+ // eventually be considered and discarded.
+
+ if (sourceType.isAssignableFrom(newIntermediateType))
+ {
+ continue;
+ }
+
+ // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
+ // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
+ // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
+ // intermediate type, hopefully closer to our eventual target type.
+
+ Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
+
+ CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
+
+ // So, every tuple that is added to the queue can take as input the sourceType.
+ // The target type may be another intermediate type, or may be something
+ // assignable to the target type, which will bring the search to a successful
+ // conclusion.
+
+ queue.addLast(compoundTuple);
+ consideredTuples.add(tuple);
+ }
+ }
+ }
+
+ /**
+ * Returns a non-null list of the tuples from the source type.
+ *
+ * @param sourceType
+ * used to locate tuples
+ * @param targetType
+ * used to add synthetic tuples
+ * @return non-null list of tuples
+ */
+ private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
+ {
+ List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
+
+ if (tuples == null)
+ {
+ tuples = Collections.emptyList();
+ }
+
+ // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
+ // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
+ // safe way (i.e., what if the Enum is defined by a class loader that gets discarded? Don't want to cause
+ // memory leaks by retaining an instance). In any case, there are edge cases where we may create
+ // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
+ // configuration), but on the whole, this is cheap and works.
+
+ if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
+ {
+ tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
+ }
+
+ return tuples;
+ }
+
+ private static <T> List<T> extend(List<T> list, T extraValue)
+ {
+ return F.flow(list).append(extraValue).toList();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
new file mode 100644
index 0000000..f1830a7
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
@@ -0,0 +1,159 @@
+// Copyright 2006 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.ioc.internal.util;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+/**
+ * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
+ * <p/>
+ * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
+ * skips java.lang.Object.
+ * <p/>
+ * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
+ * interfaces implemented by the initial class at its super classes.
+ * <p/>
+ * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
+ * <p/>
+ * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
+ * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
+ * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
+ * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
+ * <p/>
+ * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
+ * search : new InheritanceSearch(startClass)) { ... } </code>
+ * <p/>
+ * This class is not thread-safe.
+ */
+public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
+{
+ private Class searchClass;
+
+ private final Set<Class> addedInterfaces = CollectionFactory.newSet();
+
+ private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
+
+ private enum State
+ {
+ CLASS, INTERFACE, DONE
+ }
+
+ private State state;
+
+ public InheritanceSearch(Class searchClass)
+ {
+ this.searchClass = searchClass;
+
+ queueInterfaces(searchClass);
+
+ state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
+ }
+
+ private void queueInterfaces(Class searchClass)
+ {
+ for (Class intf : searchClass.getInterfaces())
+ {
+ if (addedInterfaces.contains(intf)) continue;
+
+ interfaceQueue.addLast(intf);
+ addedInterfaces.add(intf);
+ }
+ }
+
+ @Override
+ public Iterator<Class> iterator()
+ {
+ return this;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return state != State.DONE;
+ }
+
+ @Override
+ public Class next()
+ {
+ switch (state)
+ {
+ case CLASS:
+
+ Class result = searchClass;
+
+ searchClass = parentOf(searchClass);
+
+ if (searchClass == null) state = State.INTERFACE;
+ else queueInterfaces(searchClass);
+
+ return result;
+
+ case INTERFACE:
+
+ if (interfaceQueue.isEmpty())
+ {
+ state = State.DONE;
+ return Object.class;
+ }
+
+ Class intf = interfaceQueue.removeFirst();
+
+ queueInterfaces(intf);
+
+ return intf;
+
+ default:
+ throw new IllegalStateException();
+ }
+
+ }
+
+ /**
+ * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
+ * Object.class.
+ */
+ private Class parentOf(Class clazz)
+ {
+ if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
+
+ if (clazz.isArray() && clazz != Object[].class)
+ {
+ Class componentType = clazz.getComponentType();
+
+ while (componentType.isArray()) componentType = componentType.getComponentType();
+
+ if (!componentType.isPrimitive()) return Object[].class;
+ }
+
+ Class parent = clazz.getSuperclass();
+
+ return parent != Object.class ? parent : null;
+ }
+
+ /**
+ * @throws UnsupportedOperationException
+ * always
+ */
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
new file mode 100644
index 0000000..3c391e0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -0,0 +1,388 @@
+// Copyright 2006-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.ioc.internal.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+
+/**
+ * Utility methods class for the Commons package.
+ */
+public class InternalCommonsUtils {
+
+ /**
+ * @since 5.3
+ */
+ public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+ private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+ /**
+ * Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
+ * that allows multiple values for the same key.
+ *
+ * @param map
+ * to store value into
+ * @param key
+ * for which a value is added
+ * @param value
+ * to add
+ * @param <K>
+ * the type of key
+ * @param <V>
+ * the type of the list
+ */
+ public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
+ {
+ List<V> list = map.get(key);
+
+ if (list == null)
+ {
+ list = CollectionFactory.newList();
+ map.put(key, list);
+ }
+
+ list.add(value);
+ }
+
+ /**
+ * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+ * convertable to a location.
+ */
+
+ public static Location locationOf(Object location)
+ {
+ if (location == null)
+ return null;
+
+ if (location instanceof Location)
+ return (Location) location;
+
+ if (location instanceof Locatable)
+ return ((Locatable) location).getLocation();
+
+ return null;
+ }
+
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalCommonsUtils.lastTerm(propertyExpression)));
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
+
+ /**
+ * Pattern used to eliminate leading and trailing underscores and dollar signs.
+ */
+ static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+ * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+ *
+ * @param method
+ * @return short string representation
+ */
+ public static String asString(Method method)
+ {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append(method.getDeclaringClass().getName());
+ buffer.append(".");
+ buffer.append(method.getName());
+ buffer.append("(");
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ if (i > 0)
+ buffer.append(", ");
+
+ String name = method.getParameterTypes()[i].getSimpleName();
+
+ buffer.append(name);
+ }
+
+ return buffer.append(")").toString();
+ }
+
+ /**
+ * Strips leading "_" and "$" and trailing "_" from the name.
+ */
+ public static String stripMemberName(String memberName)
+ {
+ assert InternalCommonsUtils.isNonBlank(memberName);
+ Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+ if (!matcher.matches())
+ throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+ return matcher.group(1);
+ }
+
+ /**
+ * Joins together some number of elements to form a comma separated list.
+ */
+ public static String join(List elements)
+ {
+ return InternalCommonsUtils.join(elements, ", ");
+ }
+
+ /**
+ * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+ * string "(blank)".
+ *
+ * @param elements
+ * objects to be joined together
+ * @param separator
+ * used between elements when joining
+ */
+ public static String join(List elements, String separator)
+ {
+ switch (elements.size())
+ {
+ case 0:
+ return "";
+
+ case 1:
+ return elements.get(0).toString();
+
+ default:
+
+ StringBuilder buffer = new StringBuilder();
+ boolean first = true;
+
+ for (Object o : elements)
+ {
+ if (!first)
+ buffer.append(separator);
+
+ String string = String.valueOf(o);
+
+ if (string.equals(""))
+ string = "(blank)";
+
+ buffer.append(string);
+
+ first = false;
+ }
+
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+ *
+ * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+ * empty
+ */
+ public static String joinSorted(Collection elements)
+ {
+ if (elements == null || elements.isEmpty())
+ return "(none)";
+
+ List<String> list = CollectionFactory.newList();
+
+ for (Object o : elements)
+ list.add(String.valueOf(o));
+
+ Collections.sort(list);
+
+ return join(list);
+ }
+
+ /**
+ * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ */
+
+ public static boolean isBlank(String input)
+ {
+ return input == null || input.length() == 0 || input.trim().length() == 0;
+ }
+
+ /**
+ * Capitalizes a string, converting the first character to uppercase.
+ */
+ public static String capitalize(String input)
+ {
+ if (input.length() == 0)
+ return input;
+
+ return input.substring(0, 1).toUpperCase() + input.substring(1);
+ }
+
+ public static boolean isNonBlank(String input)
+ {
+ return !isBlank(input);
+ }
+
+ /**
+ * Return true if the input string contains the marker for symbols that must be expanded.
+ */
+ public static boolean containsSymbols(String input)
+ {
+ return input.contains("${");
+ }
+
+ /**
+ * Searches the string for the final period ('.') character and returns everything after that. The input string is
+ * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+ * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+ * character.
+ */
+ public static String lastTerm(String input)
+ {
+ assert isNonBlank(input);
+ int dotx = input.lastIndexOf('.');
+
+ if (dotx < 0)
+ return input;
+
+ return input.substring(dotx + 1);
+ }
+
+ /**
+ * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+ *
+ * @param map
+ * the map to extract keys from (may be null)
+ * @return the sorted keys, or the empty set if map is null
+ */
+
+ public static List<String> sortedKeys(Map map)
+ {
+ if (map == null)
+ return Collections.emptyList();
+
+ List<String> keys = CollectionFactory.newList();
+
+ for (Object o : map.keySet())
+ keys.add(String.valueOf(o));
+
+ Collections.sort(keys);
+
+ return keys;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
deleted file mode 100644
index e345593..0000000
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2006-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.ioc.internal.util;
-
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
- * Broken off Tapestry-IoC's InternalUtils.
- */
-@SuppressWarnings("all")
-public class InternalStringUtils
-{
-
- /**
- * Pattern used to eliminate leading and trailing underscores and dollar signs.
- */
- private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
- Pattern.CASE_INSENSITIVE);
-
- /**
- * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
- * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
- *
- * @param method
- * @return short string representation
- */
- public static String asString(Method method)
- {
- StringBuilder buffer = new StringBuilder();
-
- buffer.append(method.getDeclaringClass().getName());
- buffer.append(".");
- buffer.append(method.getName());
- buffer.append("(");
-
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- if (i > 0)
- buffer.append(", ");
-
- String name = method.getParameterTypes()[i].getSimpleName();
-
- buffer.append(name);
- }
-
- return buffer.append(")").toString();
- }
-
- /**
- * Strips leading "_" and "$" and trailing "_" from the name.
- */
- public static String stripMemberName(String memberName)
- {
- assert isNonBlank(memberName);
- Matcher matcher = NAME_PATTERN.matcher(memberName);
-
- if (!matcher.matches())
- throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
- return matcher.group(1);
- }
-
- /**
- * Joins together some number of elements to form a comma separated list.
- */
- public static String join(List elements)
- {
- return join(elements, ", ");
- }
-
- /**
- * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
- * string "(blank)".
- *
- * @param elements
- * objects to be joined together
- * @param separator
- * used between elements when joining
- */
- public static String join(List elements, String separator)
- {
- switch (elements.size())
- {
- case 0:
- return "";
-
- case 1:
- return elements.get(0).toString();
-
- default:
-
- StringBuilder buffer = new StringBuilder();
- boolean first = true;
-
- for (Object o : elements)
- {
- if (!first)
- buffer.append(separator);
-
- String string = String.valueOf(o);
-
- if (string.equals(""))
- string = "(blank)";
-
- buffer.append(string);
-
- first = false;
- }
-
- return buffer.toString();
- }
- }
-
- /**
- * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
- *
- * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
- * empty
- */
- public static String joinSorted(Collection elements)
- {
- if (elements == null || elements.isEmpty())
- return "(none)";
-
- List<String> list = CollectionFactory.newList();
-
- for (Object o : elements)
- list.add(String.valueOf(o));
-
- Collections.sort(list);
-
- return join(list);
- }
-
- /**
- * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
- */
-
- public static boolean isBlank(String input)
- {
- return input == null || input.length() == 0 || input.trim().length() == 0;
- }
-
- public static boolean isNonBlank(String input)
- {
- return !isBlank(input);
- }
-
- /**
- * Capitalizes a string, converting the first character to uppercase.
- */
- public static String capitalize(String input)
- {
- if (input.length() == 0)
- return input;
-
- return input.substring(0, 1).toUpperCase() + input.substring(1);
- }
-
- /**
- * Return true if the input string contains the marker for symbols that must be expanded.
- */
- public static boolean containsSymbols(String input)
- {
- return input.contains("${");
- }
-
- /**
- * Searches the string for the final period ('.') character and returns everything after that. The input string is
- * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
- * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
- * character.
- */
- public static String lastTerm(String input)
- {
- assert isNonBlank(input);
- int dotx = input.lastIndexOf('.');
-
- if (dotx < 0)
- return input;
-
- return input.substring(dotx + 1);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
new file mode 100644
index 0000000..41de363
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
@@ -0,0 +1,89 @@
+// Copyright 2012 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.ioc.internal.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base class for classes that need to manage a ReadWriteLock.
+ */
+public abstract class LockSupport
+{
+ private final Lock readLock, writeLock;
+
+ protected LockSupport()
+ {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+ readLock = lock.readLock();
+ writeLock = lock.writeLock();
+ }
+
+ /**
+ * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
+ */
+ protected final void acquireReadLock()
+ {
+ readLock.lock();
+ }
+
+ /**
+ * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
+ * this thread will have locked the write lock and no other thread will have either the read or write lock.
+ * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
+ */
+ protected final void takeWriteLock()
+ {
+ writeLock.lock();
+ }
+
+ /**
+ * Releases the shared read lock.
+ */
+ protected final void releaseReadLock()
+ {
+ readLock.unlock();
+ }
+
+ /**
+ * Releases the exclusive read lock.
+ */
+ protected final void releaseWriteLock()
+ {
+ writeLock.unlock();
+ }
+
+ /**
+ * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
+ * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
+ * inside the code that has the write lock to see if the update to perform is still necessary.
+ */
+ protected final void upgradeReadLockToWriteLock()
+ {
+ releaseReadLock();
+ // This is that instant where another thread may grab the write lock. Very rare, but possible.
+ takeWriteLock();
+ }
+
+ /**
+ * Takes the read lock then releases the write lock.
+ */
+ protected final void downgradeWriteLockToReadLock()
+ {
+ acquireReadLock();
+ releaseWriteLock();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
new file mode 100644
index 0000000..f4d8949
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
@@ -0,0 +1,65 @@
+// Copyright 2006-2013 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.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+
+import java.util.Locale;
+
+
+public class MessageFormatterImpl implements MessageFormatter
+{
+ private final String format;
+
+ private final Locale locale;
+
+ public MessageFormatterImpl(String format, Locale locale)
+ {
+ this.format = format;
+ this.locale = locale;
+ }
+
+ @Override
+ public String format(Object... args)
+ {
+ for (int i = 0; i < args.length; i++)
+ {
+ Object arg = args[i];
+
+ if (Throwable.class.isInstance(arg))
+ {
+ args[i] = ExceptionUtils.toMessage((Throwable) arg);
+ }
+ }
+
+ // Might be tempting to create a Formatter object and just keep reusing it ... but
+ // Formatters are not threadsafe.
+
+ return String.format(locale, format, args);
+ }
+
+ /**
+ * Returns the underlying format string for this formatter.
+ *
+ * @since 5.4
+ */
+ @Override
+ public String toString()
+ {
+ return format;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
new file mode 100644
index 0000000..c06ef90
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
@@ -0,0 +1,74 @@
+// Copyright 2006, 2012 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.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.util.AbstractMessages;
+
+import java.util.*;
+
+/**
+ * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
+ */
+public class MessagesImpl extends AbstractMessages
+{
+ private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
+
+ /**
+ * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
+ * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
+ *
+ * @param forClass
+ * @return Messages for the class
+ */
+ public static Messages forClass(Class forClass)
+ {
+ String className = forClass.getName();
+ String stringsClassName = className.replaceAll("Messages$", "Strings");
+
+ Locale locale = Locale.getDefault();
+
+ ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
+
+ return new MessagesImpl(locale, bundle);
+ }
+
+ public MessagesImpl(Locale locale, ResourceBundle bundle)
+ {
+ super(locale);
+
+ // Our best (threadsafe) chance to determine all the available keys.
+ Enumeration<String> e = bundle.getKeys();
+ while (e.hasMoreElements())
+ {
+ String key = e.nextElement();
+ String value = bundle.getString(key);
+
+ properties.put(key, value);
+ }
+ }
+
+ @Override
+ protected String valueForKey(String key)
+ {
+ return properties.get(key);
+ }
+
+ @Override
+ public Set<String> getKeys()
+ {
+ return properties.keySet();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index d8d8018..6e23c5b 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
*/
public TapestryException(String message, Object location, Throwable cause)
{
- this(message, locationOf(location), cause);
+ this(message, InternalCommonsUtils.locationOf(location), cause);
}
/**
@@ -71,26 +71,5 @@ public class TapestryException extends RuntimeException implements Locatable
return String.format("%s [at %s]", super.toString(), location);
}
-
- /**
- * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
- * convertable to a location.
- * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
- */
-
- private static Location locationOf(Object location)
- {
- if (location == null)
- return null;
-
- if (location instanceof Location)
- return (Location) location;
-
- if (location instanceof Locatable)
- return ((Locatable) location).getLocation();
-
- return null;
- }
-
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
new file mode 100644
index 0000000..590c337
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
@@ -0,0 +1,94 @@
+// Copyright 2006, 2009, 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.ioc.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
+ * a subclass, via the {@link #valueForKey(String)} method).
+ */
+public abstract class AbstractMessages implements Messages
+{
+ /**
+ * String key to MF instance.
+ */
+ private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
+
+ private final Locale locale;
+
+ protected AbstractMessages(Locale locale)
+ {
+ this.locale = locale;
+ }
+
+ /**
+ * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
+ * implementation should <em>ignore the case of the key</em>.
+ *
+ * @param key the key to obtain a value for (case insensitive)
+ * @return the value for the key, or null if this instance can not provide the value
+ */
+ protected abstract String valueForKey(String key);
+
+
+ @Override
+ public boolean contains(String key)
+ {
+ return valueForKey(key) != null;
+ }
+
+ @Override
+ public String get(String key)
+ {
+ if (contains(key)) return valueForKey(key);
+
+ return String.format("[[missing key: %s]]", key);
+ }
+
+ @Override
+ public MessageFormatter getFormatter(String key)
+ {
+ MessageFormatter result = cache.get(key);
+
+ if (result == null)
+ {
+ result = buildMessageFormatter(key);
+ cache.put(key, result);
+ }
+
+ return result;
+ }
+
+ private MessageFormatter buildMessageFormatter(String key)
+ {
+ String format = get(key);
+
+ return new MessageFormatterImpl(format, locale);
+ }
+
+ @Override
+ public String format(String key, Object... args)
+ {
+ return getFormatter(key).format(args);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index 8c9cb3f..b2f1386 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
import java.util.Map;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
/**
* Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
@Override
public String toString()
{
- return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
+ return String.format("AvailableValues[%s: %s]", valueType, InternalCommonsUtils.join(values));
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
new file mode 100644
index 0000000..01ef99e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
@@ -0,0 +1,195 @@
+// 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.ioc.util;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+
+/**
+ * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
+ * <p/>
+ * TimePeriods are parsed from strings.
+ * <p/>
+ * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
+ * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
+ * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p> Example: "2 h 30 m". By
+ * convention, terms are specified largest to smallest. A term without a unit is assumed to be milliseconds. Units are
+ * case insensitive ("h" or "H" are treated the same).
+ */
+public class TimeInterval
+{
+ private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
+
+ private static final long MILLISECOND = 1000l;
+
+ static
+ {
+ UNITS.put("ms", 1l);
+ UNITS.put("s", MILLISECOND);
+ UNITS.put("m", 60 * MILLISECOND);
+ UNITS.put("h", 60 * UNITS.get("m"));
+ UNITS.put("d", 24 * UNITS.get("h"));
+ UNITS.put("y", 365 * UNITS.get("d"));
+ }
+
+ /**
+ * The unit keys, sorted in descending order.
+ */
+ private static final String[] UNIT_KEYS =
+ { "y", "d", "h", "m", "s", "ms" };
+
+ private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
+
+ private final long milliseconds;
+
+ /**
+ * Creates a TimeInterval for a string.
+ *
+ * @param input
+ * the string specifying the amount of time in the period
+ */
+ public TimeInterval(String input)
+ {
+ this(parseMilliseconds(input));
+ }
+
+ public TimeInterval(long milliseconds)
+ {
+ this.milliseconds = milliseconds;
+ }
+
+ public long milliseconds()
+ {
+ return milliseconds;
+ }
+
+ public long seconds()
+ {
+ return milliseconds / MILLISECOND;
+ }
+
+ /**
+ * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
+ *
+ * @since 5.2.0
+ */
+ public String toDescription()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ String sep = "";
+
+ long remainder = milliseconds;
+
+ for (String key : UNIT_KEYS)
+ {
+ if (remainder == 0)
+ break;
+
+ long value = UNITS.get(key);
+
+ long units = remainder / value;
+
+ if (units > 0)
+ {
+ builder.append(sep);
+ builder.append(units);
+ builder.append(key);
+
+ sep = " ";
+
+ remainder = remainder % value;
+ }
+ }
+
+ return builder.toString();
+ }
+
+ static long parseMilliseconds(String input)
+ {
+ long milliseconds = 0l;
+
+ Matcher matcher = PATTERN.matcher(input);
+
+ matcher.useAnchoringBounds(true);
+
+ // TODO: Notice non matching characters and reject input, including at end
+
+ int lastMatchEnd = -1;
+
+ while (matcher.find())
+ {
+ int start = matcher.start();
+
+ if (lastMatchEnd + 1 < start)
+ {
+ String invalid = input.substring(lastMatchEnd + 1, start);
+ throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+ }
+
+ lastMatchEnd = matcher.end();
+
+ long count = Long.parseLong(matcher.group(1));
+ String units = matcher.group(2);
+
+ if (units.length() == 0)
+ {
+ milliseconds += count;
+ continue;
+ }
+
+ Long unitValue = UNITS.get(units);
+
+ if (unitValue == null)
+ throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s'). Defined units: %s.", units, input, InternalCommonsUtils.joinSorted(UNITS.keySet())));
+
+ milliseconds += count * unitValue;
+ }
+
+ if (lastMatchEnd + 1 < input.length())
+ {
+ String invalid = input.substring(lastMatchEnd + 1);
+ throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+ }
+
+ return milliseconds;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("TimeInterval[%d ms]", milliseconds);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ if (obj instanceof TimeInterval)
+ {
+ TimeInterval tp = (TimeInterval) obj;
+
+ return milliseconds == tp.milliseconds;
+ }
+
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
new file mode 100644
index 0000000..bdde866
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
@@ -0,0 +1,91 @@
+// 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.util;
+
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+
+/**
+ * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
+ * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
+ * fashion.
+ * <p>
+ * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
+ *
+ * @param <T>
+ * the type of enumeration
+ */
+public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
+{
+ private final Class<T> enumClass;
+
+ private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
+
+ public StringToEnumCoercion(Class<T> enumClass)
+ {
+ this(enumClass, enumClass.getEnumConstants());
+ }
+
+ public StringToEnumCoercion(Class<T> enumClass, T... values)
+ {
+ this.enumClass = enumClass;
+
+ for (T value : values)
+ stringToEnum.put(value.name(), value);
+ }
+
+ @Override
+ public T coerce(String input)
+ {
+ if (InternalCommonsUtils.isBlank(input))
+ return null;
+
+ T result = stringToEnum.get(input);
+
+ if (result == null)
+ {
+ String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
+ enumClass.getName());
+
+ throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
+ stringToEnum));
+ }
+
+ return result;
+ }
+
+ /**
+ * Allows an alias value (alternate) string to reference a value.
+ *
+ * @since 5.2.2
+ */
+ public StringToEnumCoercion<T> addAlias(String alias, T value)
+ {
+ stringToEnum.put(alias, value);
+
+ return this;
+ }
+
+ public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
+ {
+ return new StringToEnumCoercion<T>(enumClass);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e69377f..e032975 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
*/
public static String toUserPresentable(String id)
{
- return InternalBeanModelUtils.toUserPresentable(id);
+ return InternalUtils.toUserPresentable(id);
}
public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
*/
public static String extractIdFromPropertyExpression(String expression)
{
- return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
+ return InternalUtils.extractIdFromPropertyExpression(expression);
}
/**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
*/
public static String defaultLabel(String id, Messages messages, String propertyExpression)
{
- return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
+ return InternalUtils.defaultLabel(id, messages, propertyExpression);
}
/**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
private static String replace(String input, Pattern pattern, String replacement)
{
- return InternalBeanModelUtils.replace(input, pattern, replacement);
+ return InternalUtils.replace(input, pattern, replacement);
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
deleted file mode 100644
index 43519dc..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2009, 2012 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 org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.services.ComponentClasses;
-import org.apache.tapestry5.services.InvalidationEventHub;
-
-import javax.annotation.PostConstruct;
-import java.util.Map;
-
-public class StringInternerImpl implements StringInterner
-{
- private final Map<String, String> cache = CollectionFactory.newConcurrentMap();
-
- @PostConstruct
- public void setupInvalidation(@ComponentClasses InvalidationEventHub hub)
- {
- hub.clearOnInvalidation(cache);
- }
-
- public String intern(String string)
- {
- String result = cache.get(string);
-
- // Not yet in the cache? Add it.
-
- if (result == null)
- {
- cache.put(string, string);
- result = string;
- }
-
- return result;
- }
-
- public String format(String format, Object... arguments)
- {
- return intern(String.format(format, arguments));
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
deleted file mode 100644
index 03814f5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2006, 2008, 2009 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.ioc;
-
-/**
- * Object passed into a service contributor method that allows the method provide contributed values to the service's
- * configuration.
- * <p/>
- * A service can <em>collect</em> contributions in three different ways:
- * <ul>
- * <li>As an un-ordered collection of values</li>
- * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
- * <li>As a map of keys and values
- * </ul>
- * <p/>
- * This implementation is used for un-ordered configuration data.
- * <p/>
- * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
- * must be compatible with the type.
- */
-public interface Configuration<T>
-{
- /**
- * Adds an object to the service's contribution.
- *
- * @param object
- * to add to the service's configuration
- */
- void add(T object);
-
- /**
- * Automatically instantiates an instance of the class, with dependencies injected, and adds it to the
- * configuration. When the configuration type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the class will be created and contributed.
- *
- * @param clazz
- * what class to instantiate
- * @since 5.1.0.0
- */
- void addInstance(Class<? extends T> clazz);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
deleted file mode 100644
index 47c6026..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2006, 2008, 2009, 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.ioc;
-
-/**
- * Object passed into a service contributor method that allows the method provide contributed values to the service's
- * configuration.
- * <p/>
- * A service can <em>collect</em> contributions in three different ways:
- * <ul>
- * <li>As an un-ordered collection of values</li>
- * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
- * <li>As a map of keys and values
- * </ul>
- * <p/>
- * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
- * must be compatible with the type.
- */
-public interface MappedConfiguration<K, V>
-{
-
- /**
- * Adds a keyed object to the service's contribution.
- *
- * @param key
- * unique id for the value
- * @param value
- * to contribute
- * @throws IllegalArgumentException
- * if key is not unique
- */
- void add(K key, V value);
-
- /**
- * Overrides an existing contribution by its key.
- *
- * @param key
- * unique id of value to override
- * @param value
- * new value, or null to remove the key entirely
- * @since 5.1.0.0
- */
- void override(K key, V value);
-
- /**
- * Adds a keyed object as an instantiated instance (with dependencies injected) of a class. When the value
- * type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the value class will be created and contributed.
- *
- * @param key
- * unique id for the value
- * @param clazz
- * class to instantiate and contribute
- * @since 5.1.0.0
- */
- void addInstance(K key, Class<? extends V> clazz);
-
- /**
- * Overrides an existing contribution with a new instance. When the value
- * type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the value class will be created and contributed.
- *
- * @param key
- * unique id of value to override
- * @param clazz
- * class to instantiate as override
- */
- void overrideInstance(K key, Class<? extends V> clazz);
-}
[08/15] tapestry-5 git commit: Second pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
Second pass creating the BeanModel and Commons packages.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/1f36bb20
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/1f36bb20
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/1f36bb20
Branch: refs/heads/beanmodel-split
Commit: 1f36bb203cb0646f912125caa3bd03707aa95083
Parents: f963c7a
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 16:40:55 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 16:40:55 2014 -0200
----------------------------------------------------------------------
.../internal/antlr/PropertyExpressionLexer.g | 163 +++++++++++++++++
.../internal/antlr/PropertyExpressionParser.g | 105 +++++++++++
.../tapestry5/internal/antlr/BaseLexer.java | 54 ++++++
.../tapestry5/internal/antlr/BaseParser.java | 40 +++++
.../tapestry5/internal/antlr/package-info.java | 18 ++
.../tapestry5/internal/services/Invariant.java | 28 +++
.../services/LiteralPropertyConduit.java | 85 +++++++++
.../services/PropertyExpressionException.java | 38 ++++
.../internal/services/StringInterner.java | 43 +++++
.../org/apache/tapestry5/ioc/ObjectCreator.java | 27 +++
.../ioc/services/PlasticProxyFactory.java | 159 +++++++++++++++++
.../org/apache/tapestry5/ioc/util/Stack.java | 173 +++++++++++++++++++
.../internal/antlr/PropertyExpressionLexer.g | 163 -----------------
.../internal/antlr/PropertyExpressionParser.g | 105 -----------
.../tapestry5/internal/antlr/BaseLexer.java | 54 ------
.../tapestry5/internal/antlr/BaseParser.java | 40 -----
.../tapestry5/internal/antlr/package-info.java | 18 --
.../tapestry5/internal/services/Invariant.java | 28 ---
.../services/LiteralPropertyConduit.java | 85 ---------
.../services/PropertyExpressionException.java | 38 ----
.../internal/services/StringInterner.java | 43 -----
.../org/apache/tapestry5/ioc/ObjectCreator.java | 27 ---
.../ioc/annotations/IncompatibleChange.java | 33 ----
.../ioc/services/PlasticProxyFactory.java | 159 -----------------
.../org/apache/tapestry5/ioc/util/Stack.java | 173 -------------------
.../ioc/annotations/IncompatibleChange.java | 33 ++++
26 files changed, 966 insertions(+), 966 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
new file mode 100644
index 0000000..3b52ba9
--- /dev/null
+++ b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
@@ -0,0 +1,163 @@
+// Copyright 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.
+
+lexer grammar PropertyExpressionLexer;
+
+
+options
+{
+ superClass='org.apache.tapestry5.internal.antlr.BaseLexer';
+}
+
+@header
+{
+package org.apache.tapestry5.internal.antlr;
+}
+
+
+// Integer constant
+fragment INTEGER
+ : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
+
+// Read a property or invoke a method.
+fragment DEREF
+ : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
+
+// Range operator, ".." between two integers.
+fragment RANGEOP
+ : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
+
+// Decimal number
+fragment DECIMAL
+ : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
+
+fragment LETTER
+ : ('a'..'z'|'A'..'Z');
+fragment DIGIT
+ : '0'..'9';
+fragment SIGN
+ : ('+'|'-');
+LPAREN : '(';
+RPAREN : ')';
+LBRACKET: '[';
+RBRACKET: ']';
+COMMA : ',';
+BANG : '!';
+LBRACE : '{';
+RBRACE : '}';
+COLON : ':';
+
+fragment QUOTE
+ : '\'';
+
+// Clumsy but effective approach to case-insensitive identifiers.
+
+fragment A
+ : ('a' | 'A');
+fragment E
+ : ('e' | 'E');
+fragment F
+ : ('f' | 'F');
+fragment H
+ : ('h' | 'H');
+fragment I
+ : ('i' | 'I');
+fragment L
+ : ('l' | 'L');
+fragment N
+ : ('n'|'N');
+fragment R
+ : ('r' | 'R');
+fragment S
+ : ('s' | 'S');
+fragment T
+ : ('t' | 'T');
+fragment U
+ : ('u' | 'U');
+
+// Identifiers are case insensitive
+
+NULL : N U L L;
+TRUE : T R U E;
+FALSE : F A L S E;
+THIS : T H I S;
+
+IDENTIFIER
+ : JAVA_ID_START (JAVA_ID_PART)*
+ ;
+
+fragment
+JAVA_ID_START
+ : '\u0024'
+ | '\u0041'..'\u005a'
+ | '\u005f'
+ | '\u0061'..'\u007a'
+ | '\u00c0'..'\u00d6'
+ | '\u00d8'..'\u00f6'
+ | '\u00f8'..'\u00ff'
+ | '\u0100'..'\u1fff'
+ | '\u3040'..'\u318f'
+ | '\u3300'..'\u337f'
+ | '\u3400'..'\u3d2d'
+ | '\u4e00'..'\u9fff'
+ | '\uf900'..'\ufaff'
+ ;
+
+fragment
+JAVA_ID_PART
+ : JAVA_ID_START
+ | '\u0030'..'\u0039'
+ ;
+
+
+// The Safe Dereference operator understands not to de-reference through
+// a null.
+
+SAFEDEREF
+ : '?.';
+
+WS : (' '|'\t'|'\n'|'\r')+ { skip(); };
+
+
+// Literal strings are always inside single quotes.
+STRING
+ : QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); };
+
+
+// Special rule that uses parsing tricks to identify numbers and ranges; it's all about
+// the dot ('.').
+// Recognizes:
+// '.' as DEREF
+// '..' as RANGEOP
+// INTEGER (sign? digit+)
+// DECIMAL (sign? digits* . digits+)
+// Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10").
+
+NUMBER_OR_RANGEOP
+ : SIGN? DIGIT+
+ (
+ { input.LA(2) != '.' }? => '.' DIGIT* { $type = DECIMAL; stripLeadingPlus(); }
+ | { $type = INTEGER; stripLeadingPlus(); }
+ )
+
+ | SIGN '.' DIGIT+ { $type = DECIMAL; stripLeadingPlus(); }
+
+ | '.'
+ (
+ DIGIT+ { $type = DECIMAL; stripLeadingPlus();}
+ | '.' {$type = RANGEOP; }
+ | {$type = DEREF; }
+ )
+ ;
+
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
new file mode 100644
index 0000000..14753e6
--- /dev/null
+++ b/beanmodel/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
@@ -0,0 +1,105 @@
+// Copyright 2008, 2009, 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.
+
+parser grammar PropertyExpressionParser;
+
+
+options
+{
+ superClass='org.apache.tapestry5.internal.antlr.BaseParser';
+ output=AST;
+ ASTLabelType=CommonTree;
+ tokenVocab=PropertyExpressionLexer;
+ backtrack=true;
+}
+
+tokens
+{
+ // Parser token representing a method invocation
+ INVOKE;
+ // A List (top level, or as method parameter)
+ LIST;
+ //A Map (top level, or as method parameter)
+ MAP;
+ // Not operation (invert a boolean)
+ NOT;
+}
+
+@header
+{
+package org.apache.tapestry5.internal.antlr;
+}
+
+
+start : expression^ EOF!;
+
+expression
+ : keyword
+ | rangeOp
+ | constant
+ | propertyChain
+ | list
+ | notOp
+ | map
+ ;
+
+keyword : NULL | TRUE | FALSE | THIS;
+
+constant: INTEGER| DECIMAL | STRING;
+
+propertyChain
+ : term DEREF propertyChain -> ^(DEREF term propertyChain)
+ | term SAFEDEREF propertyChain -> ^(SAFEDEREF term propertyChain)
+ | term
+ ;
+
+term : IDENTIFIER
+ | methodInvocation
+ ;
+
+methodInvocation
+ : id=IDENTIFIER LPAREN RPAREN -> ^(INVOKE $id)
+ | id=IDENTIFIER LPAREN expressionList RPAREN -> ^(INVOKE $id expressionList)
+ ;
+
+expressionList
+ : expression (COMMA! expression)*
+ ;
+
+rangeOp
+ : from=rangeopArg RANGEOP to=rangeopArg -> ^(RANGEOP $from $to)
+ ;
+
+rangeopArg
+ : INTEGER
+ | propertyChain
+ ;
+
+list : LBRACKET RBRACKET -> ^(LIST)
+ | LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
+ ;
+
+notOp : BANG expression -> ^(NOT expression)
+ ;
+
+map : LBRACE RBRACE -> ^(MAP)
+ | LBRACE mapEntryList RBRACE -> ^(MAP mapEntryList)
+ ;
+
+mapEntryList : mapEntry (COMMA! mapEntry)*;
+
+mapEntry : mapKey COLON! expression;
+
+mapKey : keyword | constant | propertyChain;
+
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
new file mode 100644
index 0000000..442240d
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
@@ -0,0 +1,54 @@
+// Copyright 2008, 2009 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.antlr;
+
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.Lexer;
+import org.antlr.runtime.RecognizerSharedState;
+import org.antlr.runtime.RecognitionException;
+
+public abstract class BaseLexer extends Lexer
+{
+ protected BaseLexer()
+ {
+ }
+
+ protected BaseLexer(CharStream charStream,
+ RecognizerSharedState recognizerSharedState)
+ {
+ super(charStream, recognizerSharedState);
+ }
+
+ protected void stripLeadingPlus()
+ {
+ String text = getText();
+
+ // For compatibility with Tapestry 5.0, we need to allow a sign of '+', which Long.parseLong()
+ // doesn't accept. To keep things downstream simple, we eliminate the '+' here.
+
+ if (text.startsWith("+"))
+ {
+ setText(text.substring(1));
+ }
+ }
+
+ @Override
+ public void reportError(RecognitionException e)
+ {
+ throw new RuntimeException(String.format("Unable to parse input at character position %d",
+ e.charPositionInLine + 1),
+ e);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
new file mode 100644
index 0000000..212b782
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
@@ -0,0 +1,40 @@
+// Copyright 2009 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.antlr;
+
+import org.antlr.runtime.Parser;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.RecognizerSharedState;
+
+public class BaseParser extends Parser
+{
+ public BaseParser(TokenStream tokenStream)
+ {
+ super(tokenStream);
+ }
+
+ public BaseParser(TokenStream tokenStream,
+ RecognizerSharedState recognizerSharedState)
+ {
+ super(tokenStream, recognizerSharedState);
+ }
+
+ @Override
+ public void emitErrorMessage(String message)
+ {
+ // This is caught and more properly reported later.
+ throw new RuntimeException(message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
new file mode 100644
index 0000000..55be313
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
@@ -0,0 +1,18 @@
+// Copyright 2012 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.
+
+/**
+ * [INTERNAL USE ONLY] support classes related to Antlr; API subject to change
+ */
+package org.apache.tapestry5.internal.antlr;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
new file mode 100644
index 0000000..924b570
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
@@ -0,0 +1,28 @@
+// Copyright 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.internal.services;
+
+import java.lang.annotation.*;
+
+/**
+ * Special annotation that is applied to literal {@link org.apache.tapestry5.PropertyConduit}s, to inform {@link
+ * org.apache.tapestry5.internal.bindings.PropBinding} that the value is, in fact, invariant.
+ */
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Invariant
+{
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
new file mode 100644
index 0000000..1fffd4f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
@@ -0,0 +1,85 @@
+// Copyright 2008, 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 java.lang.reflect.Type;
+
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+
+/**
+ * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
+ */
+public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
+{
+ private final Class propertyType;
+
+ private final AnnotationProvider annotationProvider;
+
+ private final String description;
+
+ private final Object value;
+
+ public LiteralPropertyConduit(TypeCoercer typeCoercer, Class propertyType, AnnotationProvider annotationProvider,
+ String description, Object value)
+ {
+ super(typeCoercer);
+
+ this.propertyType = propertyType;
+ this.annotationProvider = annotationProvider;
+ this.description = description;
+
+ this.value = value;
+ }
+
+ public Object get(Object instance)
+ {
+ return value;
+ }
+
+ public void set(Object instance, Object value)
+ {
+ throw new RuntimeException("Literal values are not updateable.");
+ }
+
+ public Class getPropertyType()
+ {
+ return propertyType;
+ }
+
+ public Type getPropertyGenericType()
+ {
+ return propertyType;
+ }
+
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationProvider.getAnnotation(annotationClass);
+ }
+
+ public String getPropertyName()
+ {
+ return null;
+ }
+
+ @Override
+ public String toString()
+ {
+ return description;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
new file mode 100644
index 0000000..765c0bb
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
@@ -0,0 +1,38 @@
+// Copyright 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.internal.services;
+
+/**
+ * Exception thrown when there is a problem parsing a property expression using the ANTLR property expression grammar.
+ */
+public class PropertyExpressionException extends RuntimeException
+{
+ private final String expression;
+
+ public PropertyExpressionException(String message, String expression, Throwable cause)
+ {
+ super(message, cause);
+
+ this.expression = expression;
+ }
+
+ /**
+ * Returns the property expression containing the error.
+ */
+ public String getExpression()
+ {
+ return expression;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
new file mode 100644
index 0000000..78ee5f4
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
@@ -0,0 +1,43 @@
+// Copyright 2009 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;
+
+/**
+ * Creates "interned" strings that are unique for the same content. This is used for common description strings,
+ * particularly those used by {@link org.apache.tapestry5.Binding} instances. The internal cache of interned strings id
+ * cleared whenever the {@link org.apache.tapestry5.services.ComponentClasses} {@link
+ * org.apache.tapestry5.services.InvalidationEventHub} is invalidated (i.e., when component class files change).
+ *
+ * @since 5.1.0.0
+ */
+public interface StringInterner
+{
+ /**
+ * Interns a string.
+ *
+ * @param string the string to intern
+ * @return the input string, or another string instance with the same content
+ */
+ String intern(String string);
+
+ /**
+ * Formats a string (using {@link String#format(String, Object[])}) and returns the interned result.
+ *
+ * @param format string format
+ * @param arguments used inside the format
+ * @return formatted and interned string
+ */
+ String format(String format, Object... arguments);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
new file mode 100644
index 0000000..e7990fc
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
@@ -0,0 +1,27 @@
+// Copyright 2006, 2008, 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.ioc;
+
+/**
+ * Interface used to encapsulate any strategy used defer the creation of some object until just as needed.
+ */
+public interface ObjectCreator<T>
+{
+ /**
+ * Create and return the object. In some limited circumstances, the implementation may cache the result, returning
+ * the same object for repeated calls.
+ */
+ T createObject();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
new file mode 100644
index 0000000..75e93e4
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
@@ -0,0 +1,159 @@
+// Copyright 2011, 2012 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.ioc.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
+import org.apache.tapestry5.plastic.ClassInstantiator;
+import org.apache.tapestry5.plastic.PlasticClassListenerHub;
+import org.apache.tapestry5.plastic.PlasticClassTransformation;
+import org.apache.tapestry5.plastic.PlasticClassTransformer;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * A service used to create proxies of varying types. As a secondary concern, manages to identify the
+ * location of methods and constructors, which is important for exception reporting.
+ *
+ * @since 5.3
+ */
+public interface PlasticProxyFactory extends PlasticClassListenerHub
+{
+ /**
+ * Returns the class loader used when creating new classes, this is a child class loader
+ * of another class loader (usually, the thread's context class loader).
+ */
+ ClassLoader getClassLoader();
+
+ /**
+ * Creates a proxy object that implements the indicated interface, then invokes the callback to further
+ * configure the proxy.
+ *
+ * @param interfaceType
+ * interface implemented by proxy
+ * @param callback
+ * configures the proxy
+ * @return instantiator that can be used to create an instance of the proxy class
+ */
+ <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
+
+ /**
+ * Creates a proxy object that implements the indicated interface and indicated service implementation type,
+ * then invokes the callback to further configure the proxy.
+ *
+ * @param interfaceType
+ * interface implemented by proxy
+ * @param implementationType
+ * a class that implements the interfaceType. It can be null.
+ * @param callback
+ * configures the proxy
+ * @return instantiator that can be used to create an instance of the proxy class
+ */
+ @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+ <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
+
+ /**
+ * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
+ * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+ * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+ *
+ * @param interfaceType
+ * class proxy will extend from
+ * @return transformation from which an instantiator may be created
+ */
+ <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
+
+ /**
+ * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
+ * implementation class. This should only be
+ * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+ * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+ *
+ * @param interfaceType
+ * class proxy will extend from
+ * @param implementationType
+ * a class that implements the interfaceType. It can be null.
+ * @return transformation from which an instantiator may be created
+ */
+ @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+ <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
+
+ /**
+ * Creates a proxy instance that delegates all methods through a corresponding
+ * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+ * creator implementation may decide to
+ * cache the return value as appropriate).
+ *
+ * @param <T>
+ * type of proxy
+ * @param interfaceType
+ * interface class for proxy
+ * @param creator
+ * object responsible for creating the real object
+ * @param description
+ * the <code>toString()</code> of the proxy
+ * @return proxy instance
+ */
+ <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
+
+ /**
+ * Creates a proxy instance that delegates all methods through a corresponding
+ * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+ * creator implementation may decide to
+ * cache the return value as appropriate).
+ *
+ * @param <T>
+ * type of proxy
+ * @param interfaceType
+ * interface class for proxy
+ * @param implementationType
+ * class that implements the interface type. It may be null
+ * @param creator
+ * object responsible for creating the real object
+ * @param description
+ * the <code>toString()</code> of the proxy
+ * @return proxy instance
+ */
+ @IncompatibleChange(release = "5.4", details = "Added for TAP5-2029")
+ <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
+
+ /**
+ * Converts a method to a {@link Location}, which includes information about the source file name and line number.
+ *
+ * @param method
+ * to look up
+ * @return the location (identifying the method and possibly, the line number within the method)
+ */
+ Location getMethodLocation(Method method);
+
+ /**
+ * Return a string representation for the constructor (including class and parameters) and (if available) file name
+ * and line number.
+ *
+ * @return the location (identifying the constructor and possibly, the line number within the method)
+ */
+ Location getConstructorLocation(Constructor constructor);
+
+ /**
+ * Clears any cached information stored by the proxy factory; this is useful in Tapestry development mode
+ * when a class loader may have been discarded (because the proxy factory may indirectly keep references
+ * to classes loaded by the old class loader).
+ *
+ * @since 5.3.3
+ */
+ void clearCache();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
new file mode 100644
index 0000000..cfa13a0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
@@ -0,0 +1,173 @@
+// Copyright 2007, 2008, 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.ioc.util;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+
+/**
+ * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe.
+ *
+ * @param <E> the type of elements stored in the map
+ * @see CollectionFactory#newStack()
+ */
+public class Stack<E>
+{
+ private static final int MINIMUM_SIZE = 3;
+
+ private static final int DEFAULT_ARRAY_SIZE = 20;
+
+ private Object[] items;
+
+ private int index = -1;
+
+ /**
+ * Normal constructor supporting an initial size of 20.
+ */
+ public Stack()
+ {
+ this(DEFAULT_ARRAY_SIZE);
+ }
+
+ /**
+ * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best
+ * efficiency, set this to the maximum depth of the stack.
+ */
+ public Stack(int initialSize)
+ {
+ items = new Object[Math.max(initialSize, MINIMUM_SIZE)];
+ }
+
+ /**
+ * Returns true if the stack is empty.
+ */
+ public boolean isEmpty()
+ {
+ return index < 0;
+ }
+
+ /**
+ * Returns the number of items currently in the stack.
+ */
+ public int getDepth()
+ {
+ return index + 1;
+ }
+
+ /**
+ * Clears the stack, the same as popping off all elements.
+ */
+ public void clear()
+ {
+ for (int i = 0; i <= index; i++) items[i] = null;
+
+ index = -1;
+ }
+
+ /**
+ * Pushes a new item onto the stack.
+ */
+ public void push(E item)
+ {
+ index++;
+
+ if (index == items.length)
+ {
+ int newCapacity = (items.length * 3) / 2 + 1;
+ Object[] newItems = new Object[newCapacity];
+ System.arraycopy(items, 0, newItems, 0, items.length);
+
+ items = newItems;
+ }
+
+ items[index] = item;
+ }
+
+ /**
+ * Pops the top element off the stack and returns it.
+ *
+ * @return the top element of the stack
+ * @throws IllegalStateException if the stack is empty
+ */
+ @SuppressWarnings("unchecked")
+ public E pop()
+ {
+ checkIfEmpty();
+
+ Object result = items[index];
+
+ items[index] = null;
+
+ index--;
+
+ return (E) result;
+ }
+
+ private void checkIfEmpty()
+ {
+ if (index < 0) throw new IllegalStateException("Stack is empty.");
+ }
+
+ /**
+ * Returns the top element of the stack without affecting the stack.
+ *
+ * @return top element on the stack
+ * @throws IllegalStateException if the stack is empty
+ */
+ @SuppressWarnings("unchecked")
+ public E peek()
+ {
+ checkIfEmpty();
+
+ return (E) items[index];
+ }
+
+ /**
+ * Describes the stack, listing the element in order of depth (top element first).
+ *
+ * @return string description of the stack
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder("Stack[");
+
+ for (int i = index; i >= 0; i--)
+ {
+ if (i != index) builder.append(", ");
+
+ builder.append(String.valueOf(items[i]));
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+
+ /**
+ * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in
+ * the stack, the last object is the most shallowest (most recently pushed onto the stack). The returned array may
+ * be manipulated (it is a copy).
+ *
+ * @return the stack as an object array
+ */
+ public Object[] getSnapshot()
+ {
+ Object[] result = new Object[index + 1];
+
+ System.arraycopy(items, 0, result, 0, index + 1);
+
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g b/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
deleted file mode 100644
index 3b52ba9..0000000
--- a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 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.
-
-lexer grammar PropertyExpressionLexer;
-
-
-options
-{
- superClass='org.apache.tapestry5.internal.antlr.BaseLexer';
-}
-
-@header
-{
-package org.apache.tapestry5.internal.antlr;
-}
-
-
-// Integer constant
-fragment INTEGER
- : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
-
-// Read a property or invoke a method.
-fragment DEREF
- : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
-
-// Range operator, ".." between two integers.
-fragment RANGEOP
- : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
-
-// Decimal number
-fragment DECIMAL
- : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */};
-
-fragment LETTER
- : ('a'..'z'|'A'..'Z');
-fragment DIGIT
- : '0'..'9';
-fragment SIGN
- : ('+'|'-');
-LPAREN : '(';
-RPAREN : ')';
-LBRACKET: '[';
-RBRACKET: ']';
-COMMA : ',';
-BANG : '!';
-LBRACE : '{';
-RBRACE : '}';
-COLON : ':';
-
-fragment QUOTE
- : '\'';
-
-// Clumsy but effective approach to case-insensitive identifiers.
-
-fragment A
- : ('a' | 'A');
-fragment E
- : ('e' | 'E');
-fragment F
- : ('f' | 'F');
-fragment H
- : ('h' | 'H');
-fragment I
- : ('i' | 'I');
-fragment L
- : ('l' | 'L');
-fragment N
- : ('n'|'N');
-fragment R
- : ('r' | 'R');
-fragment S
- : ('s' | 'S');
-fragment T
- : ('t' | 'T');
-fragment U
- : ('u' | 'U');
-
-// Identifiers are case insensitive
-
-NULL : N U L L;
-TRUE : T R U E;
-FALSE : F A L S E;
-THIS : T H I S;
-
-IDENTIFIER
- : JAVA_ID_START (JAVA_ID_PART)*
- ;
-
-fragment
-JAVA_ID_START
- : '\u0024'
- | '\u0041'..'\u005a'
- | '\u005f'
- | '\u0061'..'\u007a'
- | '\u00c0'..'\u00d6'
- | '\u00d8'..'\u00f6'
- | '\u00f8'..'\u00ff'
- | '\u0100'..'\u1fff'
- | '\u3040'..'\u318f'
- | '\u3300'..'\u337f'
- | '\u3400'..'\u3d2d'
- | '\u4e00'..'\u9fff'
- | '\uf900'..'\ufaff'
- ;
-
-fragment
-JAVA_ID_PART
- : JAVA_ID_START
- | '\u0030'..'\u0039'
- ;
-
-
-// The Safe Dereference operator understands not to de-reference through
-// a null.
-
-SAFEDEREF
- : '?.';
-
-WS : (' '|'\t'|'\n'|'\r')+ { skip(); };
-
-
-// Literal strings are always inside single quotes.
-STRING
- : QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); };
-
-
-// Special rule that uses parsing tricks to identify numbers and ranges; it's all about
-// the dot ('.').
-// Recognizes:
-// '.' as DEREF
-// '..' as RANGEOP
-// INTEGER (sign? digit+)
-// DECIMAL (sign? digits* . digits+)
-// Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10").
-
-NUMBER_OR_RANGEOP
- : SIGN? DIGIT+
- (
- { input.LA(2) != '.' }? => '.' DIGIT* { $type = DECIMAL; stripLeadingPlus(); }
- | { $type = INTEGER; stripLeadingPlus(); }
- )
-
- | SIGN '.' DIGIT+ { $type = DECIMAL; stripLeadingPlus(); }
-
- | '.'
- (
- DIGIT+ { $type = DECIMAL; stripLeadingPlus();}
- | '.' {$type = RANGEOP; }
- | {$type = DEREF; }
- )
- ;
-
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g b/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
deleted file mode 100644
index 14753e6..0000000
--- a/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2008, 2009, 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.
-
-parser grammar PropertyExpressionParser;
-
-
-options
-{
- superClass='org.apache.tapestry5.internal.antlr.BaseParser';
- output=AST;
- ASTLabelType=CommonTree;
- tokenVocab=PropertyExpressionLexer;
- backtrack=true;
-}
-
-tokens
-{
- // Parser token representing a method invocation
- INVOKE;
- // A List (top level, or as method parameter)
- LIST;
- //A Map (top level, or as method parameter)
- MAP;
- // Not operation (invert a boolean)
- NOT;
-}
-
-@header
-{
-package org.apache.tapestry5.internal.antlr;
-}
-
-
-start : expression^ EOF!;
-
-expression
- : keyword
- | rangeOp
- | constant
- | propertyChain
- | list
- | notOp
- | map
- ;
-
-keyword : NULL | TRUE | FALSE | THIS;
-
-constant: INTEGER| DECIMAL | STRING;
-
-propertyChain
- : term DEREF propertyChain -> ^(DEREF term propertyChain)
- | term SAFEDEREF propertyChain -> ^(SAFEDEREF term propertyChain)
- | term
- ;
-
-term : IDENTIFIER
- | methodInvocation
- ;
-
-methodInvocation
- : id=IDENTIFIER LPAREN RPAREN -> ^(INVOKE $id)
- | id=IDENTIFIER LPAREN expressionList RPAREN -> ^(INVOKE $id expressionList)
- ;
-
-expressionList
- : expression (COMMA! expression)*
- ;
-
-rangeOp
- : from=rangeopArg RANGEOP to=rangeopArg -> ^(RANGEOP $from $to)
- ;
-
-rangeopArg
- : INTEGER
- | propertyChain
- ;
-
-list : LBRACKET RBRACKET -> ^(LIST)
- | LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
- ;
-
-notOp : BANG expression -> ^(NOT expression)
- ;
-
-map : LBRACE RBRACE -> ^(MAP)
- | LBRACE mapEntryList RBRACE -> ^(MAP mapEntryList)
- ;
-
-mapEntryList : mapEntry (COMMA! mapEntry)*;
-
-mapEntry : mapKey COLON! expression;
-
-mapKey : keyword | constant | propertyChain;
-
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
deleted file mode 100644
index 442240d..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseLexer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2008, 2009 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.antlr;
-
-import org.antlr.runtime.CharStream;
-import org.antlr.runtime.Lexer;
-import org.antlr.runtime.RecognizerSharedState;
-import org.antlr.runtime.RecognitionException;
-
-public abstract class BaseLexer extends Lexer
-{
- protected BaseLexer()
- {
- }
-
- protected BaseLexer(CharStream charStream,
- RecognizerSharedState recognizerSharedState)
- {
- super(charStream, recognizerSharedState);
- }
-
- protected void stripLeadingPlus()
- {
- String text = getText();
-
- // For compatibility with Tapestry 5.0, we need to allow a sign of '+', which Long.parseLong()
- // doesn't accept. To keep things downstream simple, we eliminate the '+' here.
-
- if (text.startsWith("+"))
- {
- setText(text.substring(1));
- }
- }
-
- @Override
- public void reportError(RecognitionException e)
- {
- throw new RuntimeException(String.format("Unable to parse input at character position %d",
- e.charPositionInLine + 1),
- e);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
deleted file mode 100644
index 212b782..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/BaseParser.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2009 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.antlr;
-
-import org.antlr.runtime.Parser;
-import org.antlr.runtime.TokenStream;
-import org.antlr.runtime.RecognizerSharedState;
-
-public class BaseParser extends Parser
-{
- public BaseParser(TokenStream tokenStream)
- {
- super(tokenStream);
- }
-
- public BaseParser(TokenStream tokenStream,
- RecognizerSharedState recognizerSharedState)
- {
- super(tokenStream, recognizerSharedState);
- }
-
- @Override
- public void emitErrorMessage(String message)
- {
- // This is caught and more properly reported later.
- throw new RuntimeException(message);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
deleted file mode 100644
index 55be313..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/antlr/package-info.java
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2012 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.
-
-/**
- * [INTERNAL USE ONLY] support classes related to Antlr; API subject to change
- */
-package org.apache.tapestry5.internal.antlr;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
deleted file mode 100644
index 924b570..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/Invariant.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 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.internal.services;
-
-import java.lang.annotation.*;
-
-/**
- * Special annotation that is applied to literal {@link org.apache.tapestry5.PropertyConduit}s, to inform {@link
- * org.apache.tapestry5.internal.bindings.PropBinding} that the value is, in fact, invariant.
- */
-@Target({ElementType.PARAMETER, ElementType.FIELD})
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface Invariant
-{
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
deleted file mode 100644
index 1fffd4f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2008, 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 java.lang.reflect.Type;
-
-import org.apache.tapestry5.internal.InternalPropertyConduit;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.services.TypeCoercer;
-
-/**
- * A PropertyConduit for a literal value in an expression, such as a number, or "true", "false" or "null".
- */
-public class LiteralPropertyConduit extends PropertyConduitDelegate implements InternalPropertyConduit
-{
- private final Class propertyType;
-
- private final AnnotationProvider annotationProvider;
-
- private final String description;
-
- private final Object value;
-
- public LiteralPropertyConduit(TypeCoercer typeCoercer, Class propertyType, AnnotationProvider annotationProvider,
- String description, Object value)
- {
- super(typeCoercer);
-
- this.propertyType = propertyType;
- this.annotationProvider = annotationProvider;
- this.description = description;
-
- this.value = value;
- }
-
- public Object get(Object instance)
- {
- return value;
- }
-
- public void set(Object instance, Object value)
- {
- throw new RuntimeException("Literal values are not updateable.");
- }
-
- public Class getPropertyType()
- {
- return propertyType;
- }
-
- public Type getPropertyGenericType()
- {
- return propertyType;
- }
-
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationProvider.getAnnotation(annotationClass);
- }
-
- public String getPropertyName()
- {
- return null;
- }
-
- @Override
- public String toString()
- {
- return description;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
deleted file mode 100644
index 765c0bb..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyExpressionException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 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.internal.services;
-
-/**
- * Exception thrown when there is a problem parsing a property expression using the ANTLR property expression grammar.
- */
-public class PropertyExpressionException extends RuntimeException
-{
- private final String expression;
-
- public PropertyExpressionException(String message, String expression, Throwable cause)
- {
- super(message, cause);
-
- this.expression = expression;
- }
-
- /**
- * Returns the property expression containing the error.
- */
- public String getExpression()
- {
- return expression;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
deleted file mode 100644
index 78ee5f4..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInterner.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2009 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;
-
-/**
- * Creates "interned" strings that are unique for the same content. This is used for common description strings,
- * particularly those used by {@link org.apache.tapestry5.Binding} instances. The internal cache of interned strings id
- * cleared whenever the {@link org.apache.tapestry5.services.ComponentClasses} {@link
- * org.apache.tapestry5.services.InvalidationEventHub} is invalidated (i.e., when component class files change).
- *
- * @since 5.1.0.0
- */
-public interface StringInterner
-{
- /**
- * Interns a string.
- *
- * @param string the string to intern
- * @return the input string, or another string instance with the same content
- */
- String intern(String string);
-
- /**
- * Formats a string (using {@link String#format(String, Object[])}) and returns the interned result.
- *
- * @param format string format
- * @param arguments used inside the format
- * @return formatted and interned string
- */
- String format(String format, Object... arguments);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
deleted file mode 100644
index e7990fc..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectCreator.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2006, 2008, 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.ioc;
-
-/**
- * Interface used to encapsulate any strategy used defer the creation of some object until just as needed.
- */
-public interface ObjectCreator<T>
-{
- /**
- * Create and return the object. In some limited circumstances, the implementation may cache the result, returning
- * the same object for repeated calls.
- */
- T createObject();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
deleted file mode 100644
index ffc9490..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.ioc.annotations;
-
-import java.lang.annotation.*;
-
-@Target({ElementType.METHOD, ElementType.FIELD})
-@Retention(RetentionPolicy.CLASS)
-@Documented
-public @interface IncompatibleChange
-{
- /**
- * Identifies the release in which the signature of the method was modified.
- *
- * @return a release number, e.g., "5.4"
- */
- String release();
-
- /**
- * Short string describing what changed.
- */
- String details();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
deleted file mode 100644
index 75e93e4..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2011, 2012 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.ioc.services;
-
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
-import org.apache.tapestry5.plastic.ClassInstantiator;
-import org.apache.tapestry5.plastic.PlasticClassListenerHub;
-import org.apache.tapestry5.plastic.PlasticClassTransformation;
-import org.apache.tapestry5.plastic.PlasticClassTransformer;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
-/**
- * A service used to create proxies of varying types. As a secondary concern, manages to identify the
- * location of methods and constructors, which is important for exception reporting.
- *
- * @since 5.3
- */
-public interface PlasticProxyFactory extends PlasticClassListenerHub
-{
- /**
- * Returns the class loader used when creating new classes, this is a child class loader
- * of another class loader (usually, the thread's context class loader).
- */
- ClassLoader getClassLoader();
-
- /**
- * Creates a proxy object that implements the indicated interface, then invokes the callback to further
- * configure the proxy.
- *
- * @param interfaceType
- * interface implemented by proxy
- * @param callback
- * configures the proxy
- * @return instantiator that can be used to create an instance of the proxy class
- */
- <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
-
- /**
- * Creates a proxy object that implements the indicated interface and indicated service implementation type,
- * then invokes the callback to further configure the proxy.
- *
- * @param interfaceType
- * interface implemented by proxy
- * @param implementationType
- * a class that implements the interfaceType. It can be null.
- * @param callback
- * configures the proxy
- * @return instantiator that can be used to create an instance of the proxy class
- */
- @IncompatibleChange(release = "5.4", details = "TAP5-2029")
- <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
-
- /**
- * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
- * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
- * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
- *
- * @param interfaceType
- * class proxy will extend from
- * @return transformation from which an instantiator may be created
- */
- <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
-
- /**
- * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
- * implementation class. This should only be
- * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
- * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
- *
- * @param interfaceType
- * class proxy will extend from
- * @param implementationType
- * a class that implements the interfaceType. It can be null.
- * @return transformation from which an instantiator may be created
- */
- @IncompatibleChange(release = "5.4", details = "TAP5-2029")
- <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
-
- /**
- * Creates a proxy instance that delegates all methods through a corresponding
- * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
- * creator implementation may decide to
- * cache the return value as appropriate).
- *
- * @param <T>
- * type of proxy
- * @param interfaceType
- * interface class for proxy
- * @param creator
- * object responsible for creating the real object
- * @param description
- * the <code>toString()</code> of the proxy
- * @return proxy instance
- */
- <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
-
- /**
- * Creates a proxy instance that delegates all methods through a corresponding
- * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
- * creator implementation may decide to
- * cache the return value as appropriate).
- *
- * @param <T>
- * type of proxy
- * @param interfaceType
- * interface class for proxy
- * @param implementationType
- * class that implements the interface type. It may be null
- * @param creator
- * object responsible for creating the real object
- * @param description
- * the <code>toString()</code> of the proxy
- * @return proxy instance
- */
- @IncompatibleChange(release = "5.4", details = "Added for TAP5-2029")
- <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
-
- /**
- * Converts a method to a {@link Location}, which includes information about the source file name and line number.
- *
- * @param method
- * to look up
- * @return the location (identifying the method and possibly, the line number within the method)
- */
- Location getMethodLocation(Method method);
-
- /**
- * Return a string representation for the constructor (including class and parameters) and (if available) file name
- * and line number.
- *
- * @return the location (identifying the constructor and possibly, the line number within the method)
- */
- Location getConstructorLocation(Constructor constructor);
-
- /**
- * Clears any cached information stored by the proxy factory; this is useful in Tapestry development mode
- * when a class loader may have been discarded (because the proxy factory may indirectly keep references
- * to classes loaded by the old class loader).
- *
- * @since 5.3.3
- */
- void clearCache();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
deleted file mode 100644
index cfa13a0..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/Stack.java
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2007, 2008, 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.ioc.util;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-
-/**
- * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe.
- *
- * @param <E> the type of elements stored in the map
- * @see CollectionFactory#newStack()
- */
-public class Stack<E>
-{
- private static final int MINIMUM_SIZE = 3;
-
- private static final int DEFAULT_ARRAY_SIZE = 20;
-
- private Object[] items;
-
- private int index = -1;
-
- /**
- * Normal constructor supporting an initial size of 20.
- */
- public Stack()
- {
- this(DEFAULT_ARRAY_SIZE);
- }
-
- /**
- * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best
- * efficiency, set this to the maximum depth of the stack.
- */
- public Stack(int initialSize)
- {
- items = new Object[Math.max(initialSize, MINIMUM_SIZE)];
- }
-
- /**
- * Returns true if the stack is empty.
- */
- public boolean isEmpty()
- {
- return index < 0;
- }
-
- /**
- * Returns the number of items currently in the stack.
- */
- public int getDepth()
- {
- return index + 1;
- }
-
- /**
- * Clears the stack, the same as popping off all elements.
- */
- public void clear()
- {
- for (int i = 0; i <= index; i++) items[i] = null;
-
- index = -1;
- }
-
- /**
- * Pushes a new item onto the stack.
- */
- public void push(E item)
- {
- index++;
-
- if (index == items.length)
- {
- int newCapacity = (items.length * 3) / 2 + 1;
- Object[] newItems = new Object[newCapacity];
- System.arraycopy(items, 0, newItems, 0, items.length);
-
- items = newItems;
- }
-
- items[index] = item;
- }
-
- /**
- * Pops the top element off the stack and returns it.
- *
- * @return the top element of the stack
- * @throws IllegalStateException if the stack is empty
- */
- @SuppressWarnings("unchecked")
- public E pop()
- {
- checkIfEmpty();
-
- Object result = items[index];
-
- items[index] = null;
-
- index--;
-
- return (E) result;
- }
-
- private void checkIfEmpty()
- {
- if (index < 0) throw new IllegalStateException("Stack is empty.");
- }
-
- /**
- * Returns the top element of the stack without affecting the stack.
- *
- * @return top element on the stack
- * @throws IllegalStateException if the stack is empty
- */
- @SuppressWarnings("unchecked")
- public E peek()
- {
- checkIfEmpty();
-
- return (E) items[index];
- }
-
- /**
- * Describes the stack, listing the element in order of depth (top element first).
- *
- * @return string description of the stack
- */
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder("Stack[");
-
- for (int i = index; i >= 0; i--)
- {
- if (i != index) builder.append(", ");
-
- builder.append(String.valueOf(items[i]));
- }
-
- builder.append("]");
-
- return builder.toString();
- }
-
- /**
- * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in
- * the stack, the last object is the most shallowest (most recently pushed onto the stack). The returned array may
- * be manipulated (it is a copy).
- *
- * @return the stack as an object array
- */
- public Object[] getSnapshot()
- {
- Object[] result = new Object[index + 1];
-
- System.arraycopy(items, 0, result, 0, index + 1);
-
- return result;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1f36bb20/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
new file mode 100644
index 0000000..ffc9490
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/IncompatibleChange.java
@@ -0,0 +1,33 @@
+// 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.ioc.annotations;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.CLASS)
+@Documented
+public @interface IncompatibleChange
+{
+ /**
+ * Identifies the release in which the signature of the method was modified.
+ *
+ * @return a release number, e.g., "5.4"
+ */
+ String release();
+
+ /**
+ * Short string describing what changed.
+ */
+ String details();
+}
[09/15] tapestry-5 git commit: Second pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
Second pass creating the BeanModel and Commons packages.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/c9e97d64
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/c9e97d64
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/c9e97d64
Branch: refs/heads/beanmodel-split
Commit: c9e97d64a51b25c875d5daa94d2f607e4ed299f3
Parents: 1f36bb2
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 16:42:10 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 16:42:10 2014 -0200
----------------------------------------------------------------------
beanmodel/.gitignore | 4 +
beanmodel/build.gradle | 51 ++++-
.../tapestry5/internal/BeanModelUtils.java | 145 +++++++++++++
.../internal/beaneditor/BeanModelImpl.java | 4 +-
.../internal/beaneditor/PropertyModelImpl.java | 14 +-
.../services/PropertyConduitDelegate.java | 1 -
.../services/PropertyConduitSourceImpl.java | 10 +-
.../org/apache/tapestry5/ioc/ObjectLocator.java | 3 +-
.../ioc/internal/util/InternalStringUtils.java | 203 +++++++++++++++++++
.../ioc/internal/util/TapestryException.java | 23 ++-
.../tapestry5/ioc/util/AvailableValues.java | 4 +-
tapestry-core/build.gradle | 37 ----
.../internal/TapestryInternalUtils.java | 46 +----
.../ioc/internal/util/InternalUtils.java | 142 +++----------
14 files changed, 472 insertions(+), 215 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/.gitignore
----------------------------------------------------------------------
diff --git a/beanmodel/.gitignore b/beanmodel/.gitignore
new file mode 100644
index 0000000..f739972
--- /dev/null
+++ b/beanmodel/.gitignore
@@ -0,0 +1,4 @@
+docs
+/.externalToolBuilders
+src/main/generated
+src/test/generated
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
index ccdeb37..c09ebdd 100644
--- a/beanmodel/build.gradle
+++ b/beanmodel/build.gradle
@@ -6,7 +6,18 @@ description = "Fast class property discovery, reading and writing library based
//apply plugin: JavaPlugin
buildDir = 'target/gradle-build'
-
+
+project.ext {
+ antlrSource = "src/main/antlr"
+ mainGeneratedDir = "src/main/generated"
+ testGeneratedDir = "src/test/generated"
+ antlrOutput = "$mainGeneratedDir/antlr"
+}
+
+configurations {
+ antlr3
+}
+
project.ext.libraryVersions = [
jcache: '1.0.0',
]
@@ -15,12 +26,50 @@ dependencies {
compile project(":plastic")
compile project(":tapestry5-annotations")
compile project(":commons")
+
+ // Antlr3 tool path used with the antlr3 task
+ antlr3 "org.antlr:antlr:3.5.2"
+
// 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"
}
}
+// This may spin out as a plugin once we've got the details down pat
+
+task generateGrammarSource(type: JavaExec) {
+ description "Generates Java sources from Antlr3 grammars."
+ inputs.source fileTree(dir: antlrSource, include: "**/*.g")
+ outputs.dir file(antlrOutput)
+
+ classpath configurations.antlr3
+
+ main "org.antlr.Tool"
+ args "-o", "${antlrOutput}/org/apache/tapestry5/internal/antlr"
+ args inputs.sourceFiles
+
+ doFirst {
+ logger.info "Executing Antlr3 grammar generation:\n${commandLine.join(' ')}"
+ }
+}
+
+sourceSets {
+ main {
+ output.dir(antlrOutput, builtBy: generateGrammarSource)
+ java {
+ srcDir antlrOutput
+ }
+ }
+}
+
+clean.delete mainGeneratedDir, testGeneratedDir
+
+compileJava {
+ dependsOn generateGrammarSource
+ options.fork(memoryMaximumSize: '512m')
+}
+
jar {
manifest {
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
new file mode 100644
index 0000000..08cb88a
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
@@ -0,0 +1,145 @@
+// 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.internal;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+
+/**
+ * Some methods broken off tapestry-core's InternalUtils to avoid bringing the whole class
+ * plus its multiple dependencies to the BeanModel package.
+ */
+public class BeanModelUtils {
+
+ public static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+ /**
+ * @since 5.3
+ */
+ private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
+
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/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
index 26eb309..b72a3d6 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
@@ -22,7 +22,7 @@ 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.internal.util.InternalStringUtils;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.UnknownValueException;
@@ -93,7 +93,7 @@ public class BeanModelImpl<T> implements BeanModel<T>
private void validateNewPropertyName(String propertyName)
{
- assert InternalUtils.isNonBlank(propertyName);
+ assert InternalStringUtils.isNonBlank(propertyName);
if (properties.containsKey(propertyName))
throw new RuntimeException(String.format(
"Bean editor model for %s already contains a property model for property '%s'.",
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/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
index 703ce44..b21e5bb 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -14,17 +14,17 @@
package org.apache.tapestry5.internal.beaneditor;
+import java.lang.annotation.Annotation;
+
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.internal.BeanModelUtils;
import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
-import java.lang.annotation.Annotation;
-
@SuppressWarnings("all")
public class PropertyModelImpl implements PropertyModel
{
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
this.name = name;
this.conduit = conduit;
- id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
+ id = BeanModelUtils.extractIdFromPropertyExpression(name);
- label = TapestryInternalUtils.defaultLabel(id, messages, name);
+ label = BeanModelUtils.defaultLabel(id, messages, name);
// TAP5-2305
if (conduit != null)
@@ -87,7 +87,7 @@ public class PropertyModelImpl implements PropertyModel
public PropertyModel label(String label)
{
- assert InternalUtils.isNonBlank(label);
+ assert InternalStringUtils.isNonBlank(label);
this.label = label;
return this;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/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
index 1242031..3849103 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
@@ -19,7 +19,6 @@ 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;
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 701420f..83f67fa 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -19,6 +19,7 @@ import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.Tree;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.PropertyConduit2;
+import org.apache.tapestry5.internal.BeanModelUtils;
import org.apache.tapestry5.internal.InternalPropertyConduit;
import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -29,7 +30,7 @@ import org.apache.tapestry5.ioc.annotations.PostInjection;
import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
import org.apache.tapestry5.ioc.services.*;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.ExceptionUtils;
@@ -1106,7 +1107,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
- InternalUtils.joinSorted(tokenNames));
+ InternalStringUtils.joinSorted(tokenNames));
return new RuntimeException(message);
}
@@ -1259,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
Type returnType = GenericsUtils.extractActualType(activeType, method);
- return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+ return new Term(returnType, toUniqueId(method), BeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
{
@@ -1363,7 +1364,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
public PropertyConduit create(Class rootClass, String expression)
{
assert rootClass != null;
- assert InternalUtils.isNonBlank(expression);
+ assert InternalStringUtils.isNonBlank(expression);
MultiKey key = new MultiKey(rootClass, expression);
@@ -1560,4 +1561,5 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
return builder.append(")").toString();
}
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
index 81d1f77..e60c0d9 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 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.
@@ -15,7 +15,6 @@
package org.apache.tapestry5.ioc;
import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.services.MasterObjectProvider;
import java.lang.annotation.Annotation;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
new file mode 100644
index 0000000..e345593
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
@@ -0,0 +1,203 @@
+// Copyright 2006-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.ioc.internal.util;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
+ * Broken off Tapestry-IoC's InternalUtils.
+ */
+@SuppressWarnings("all")
+public class InternalStringUtils
+{
+
+ /**
+ * Pattern used to eliminate leading and trailing underscores and dollar signs.
+ */
+ private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+ * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+ *
+ * @param method
+ * @return short string representation
+ */
+ public static String asString(Method method)
+ {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append(method.getDeclaringClass().getName());
+ buffer.append(".");
+ buffer.append(method.getName());
+ buffer.append("(");
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ if (i > 0)
+ buffer.append(", ");
+
+ String name = method.getParameterTypes()[i].getSimpleName();
+
+ buffer.append(name);
+ }
+
+ return buffer.append(")").toString();
+ }
+
+ /**
+ * Strips leading "_" and "$" and trailing "_" from the name.
+ */
+ public static String stripMemberName(String memberName)
+ {
+ assert isNonBlank(memberName);
+ Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+ if (!matcher.matches())
+ throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+ return matcher.group(1);
+ }
+
+ /**
+ * Joins together some number of elements to form a comma separated list.
+ */
+ public static String join(List elements)
+ {
+ return join(elements, ", ");
+ }
+
+ /**
+ * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+ * string "(blank)".
+ *
+ * @param elements
+ * objects to be joined together
+ * @param separator
+ * used between elements when joining
+ */
+ public static String join(List elements, String separator)
+ {
+ switch (elements.size())
+ {
+ case 0:
+ return "";
+
+ case 1:
+ return elements.get(0).toString();
+
+ default:
+
+ StringBuilder buffer = new StringBuilder();
+ boolean first = true;
+
+ for (Object o : elements)
+ {
+ if (!first)
+ buffer.append(separator);
+
+ String string = String.valueOf(o);
+
+ if (string.equals(""))
+ string = "(blank)";
+
+ buffer.append(string);
+
+ first = false;
+ }
+
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+ *
+ * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+ * empty
+ */
+ public static String joinSorted(Collection elements)
+ {
+ if (elements == null || elements.isEmpty())
+ return "(none)";
+
+ List<String> list = CollectionFactory.newList();
+
+ for (Object o : elements)
+ list.add(String.valueOf(o));
+
+ Collections.sort(list);
+
+ return join(list);
+ }
+
+ /**
+ * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ */
+
+ public static boolean isBlank(String input)
+ {
+ return input == null || input.length() == 0 || input.trim().length() == 0;
+ }
+
+ public static boolean isNonBlank(String input)
+ {
+ return !isBlank(input);
+ }
+
+ /**
+ * Capitalizes a string, converting the first character to uppercase.
+ */
+ public static String capitalize(String input)
+ {
+ if (input.length() == 0)
+ return input;
+
+ return input.substring(0, 1).toUpperCase() + input.substring(1);
+ }
+
+ /**
+ * Return true if the input string contains the marker for symbols that must be expanded.
+ */
+ public static boolean containsSymbols(String input)
+ {
+ return input.contains("${");
+ }
+
+ /**
+ * Searches the string for the final period ('.') character and returns everything after that. The input string is
+ * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+ * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+ * character.
+ */
+ public static String lastTerm(String input)
+ {
+ assert isNonBlank(input);
+ int dotx = input.lastIndexOf('.');
+
+ if (dotx < 0)
+ return input;
+
+ return input.substring(dotx + 1);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index ef217cb..d8d8018 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
*/
public TapestryException(String message, Object location, Throwable cause)
{
- this(message, InternalUtils.locationOf(location), cause);
+ this(message, locationOf(location), cause);
}
/**
@@ -71,5 +71,26 @@ public class TapestryException extends RuntimeException implements Locatable
return String.format("%s [at %s]", super.toString(), location);
}
+
+ /**
+ * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+ * convertable to a location.
+ * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
+ */
+
+ private static Location locationOf(Object location)
+ {
+ if (location == null)
+ return null;
+
+ if (location instanceof Location)
+ return (Location) location;
+
+ if (location instanceof Locatable)
+ return ((Locatable) location).getLocation();
+
+ return null;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index c4c5c6d..8c9cb3f 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
import java.util.Map;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
/**
* Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
@Override
public String toString()
{
- return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
+ return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-core/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index 584200a..d35c166 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -8,11 +8,6 @@ project.ext {
antlrSource = "src/main/antlr"
mainGeneratedDir = "src/main/generated"
testGeneratedDir = "src/test/generated"
- antlrOutput = "$mainGeneratedDir/antlr"
-}
-
-configurations {
- antlr3
}
dependencies {
@@ -27,30 +22,9 @@ dependencies {
compile "commons-codec:commons-codec:1.5"
- // Antlr3 tool path used with the antlr3 task
- antlr3 "org.antlr:antlr:3.5.2"
-
testRuntime "org.hsqldb:hsqldb:1.8.0.10"
}
-// This may spin out as a plugin once we've got the details down pat
-
-task generateGrammarSource(type: JavaExec) {
- description "Generates Java sources from Antlr3 grammars."
- inputs.source fileTree(dir: antlrSource, include: "**/*.g")
- outputs.dir file(antlrOutput)
-
- classpath configurations.antlr3
-
- main "org.antlr.Tool"
- args "-o", "${antlrOutput}/org/apache/tapestry5/internal/antlr"
- args inputs.sourceFiles
-
- doFirst {
- logger.info "Executing Antlr3 grammar generation:\n${commandLine.join(' ')}"
- }
-}
-
task preprocessCoffeeScript(type: PreprocessCoffeeScript) {
}
@@ -73,23 +47,12 @@ sourceSets {
main {
output.dir(compileCoffeeScript.outputDir, builtBy: compileCoffeeScript)
output.dir(compileProcessedCoffeescript.outputDir, builtBy: compileProcessedCoffeescript)
- output.dir(antlrOutput, builtBy: generateGrammarSource)
- java {
- srcDir antlrOutput
- }
}
test {
output.dir(compileTestCoffeeScript.outputDir, builtBy: compileTestCoffeeScript)
}
}
-clean.delete mainGeneratedDir, testGeneratedDir
-
-compileJava {
- dependsOn generateGrammarSource
- options.fork(memoryMaximumSize: '512m')
-}
-
// Not sure why this is necessary:
compileTestGroovy.dependsOn compileTestJava
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index 3435d64..aba7225 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,40 +59,7 @@ public class TapestryInternalUtils
*/
public static String toUserPresentable(String id)
{
- StringBuilder builder = new StringBuilder(id.length() * 2);
-
- char[] chars = id.toCharArray();
- boolean postSpace = true;
- boolean upcaseNext = true;
-
- for (char ch : chars)
- {
- if (upcaseNext)
- {
- builder.append(Character.toUpperCase(ch));
- upcaseNext = false;
-
- continue;
- }
-
- if (ch == '_')
- {
- builder.append(' ');
- upcaseNext = true;
- continue;
- }
-
- boolean upperCase = Character.isUpperCase(ch);
-
- if (upperCase && !postSpace)
- builder.append(' ');
-
- builder.append(ch);
-
- postSpace = upperCase;
- }
-
- return builder.toString();
+ return BeanModelUtils.toUserPresentable(id);
}
public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -261,7 +228,7 @@ public class TapestryInternalUtils
*/
public static String extractIdFromPropertyExpression(String expression)
{
- return replace(expression, NON_WORD_PATTERN, "");
+ return BeanModelUtils.extractIdFromPropertyExpression(expression);
}
/**
@@ -270,12 +237,7 @@ public class TapestryInternalUtils
*/
public static String defaultLabel(String id, Messages messages, String propertyExpression)
{
- String key = id + "-label";
-
- if (messages.contains(key))
- return messages.get(key);
-
- return toUserPresentable(extractIdFromPropertyExpression(lastTerm(propertyExpression)));
+ return BeanModelUtils.defaultLabel(id, messages, propertyExpression);
}
/**
@@ -342,7 +304,7 @@ public class TapestryInternalUtils
private static String replace(String input, Pattern pattern, String replacement)
{
- return pattern.matcher(input).replaceAll(replacement);
+ return BeanModelUtils.replace(input, pattern, replacement);
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index e9e7806..a40f984 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,16 +17,16 @@ package org.apache.tapestry5.ioc.internal.util;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.func.Mapper;
import org.apache.tapestry5.func.Predicate;
+import org.apache.tapestry5.internal.BeanModelUtils;
import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
import org.apache.tapestry5.ioc.def.*;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
import org.apache.tapestry5.ioc.internal.ServiceDefImpl;
import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
import org.apache.tapestry5.ioc.util.ExceptionUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
import org.slf4j.Logger;
import javax.annotation.PostConstruct;
@@ -56,18 +56,6 @@ public class InternalUtils
public static final boolean SERVICE_CLASS_RELOADING_ENABLED = Boolean.parseBoolean(System.getProperty(
IOCConstants.SERVICE_CLASS_RELOADING_ENABLED, "true"));
-
- /**
- * Pattern used to eliminate leading and trailing underscores and dollar signs.
- */
- private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
- Pattern.CASE_INSENSITIVE);
-
- /**
- * @since 5.3
- */
- public static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-
/**
* Converts a method to a user presentable string using a {@link PlasticProxyFactory} to obtain a {@link Location}
* (where possible). {@link #asString(Method)} is used under the covers, to present a detailed, but not excessive,
@@ -92,27 +80,11 @@ public class InternalUtils
*
* @param method
* @return short string representation
+ * @deprecated use {@link InternalStringUtils#asString(Method)} instead.
*/
public static String asString(Method method)
{
- StringBuilder buffer = new StringBuilder();
-
- buffer.append(method.getDeclaringClass().getName());
- buffer.append(".");
- buffer.append(method.getName());
- buffer.append("(");
-
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- if (i > 0)
- buffer.append(", ");
-
- String name = method.getParameterTypes()[i].getSimpleName();
-
- buffer.append(name);
- }
-
- return buffer.append(")").toString();
+ return InternalStringUtils.asString(method);
}
/**
@@ -131,16 +103,11 @@ public class InternalUtils
/**
* Strips leading "_" and "$" and trailing "_" from the name.
+ * @deprecated use {@link InternalStringUtils#stripMemberName(String)} instead.
*/
public static String stripMemberName(String memberName)
{
- assert InternalUtils.isNonBlank(memberName);
- Matcher matcher = NAME_PATTERN.matcher(memberName);
-
- if (!matcher.matches())
- throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
- return matcher.group(1);
+ return InternalStringUtils.stripMemberName(memberName);
}
/**
@@ -425,10 +392,11 @@ public class InternalUtils
/**
* Joins together some number of elements to form a comma separated list.
+ * @deprecated use {@link InternalStringUtils#join(List)} instead.
*/
public static String join(List elements)
{
- return join(elements, ", ");
+ return InternalStringUtils.join(elements);
}
/**
@@ -439,39 +407,11 @@ public class InternalUtils
* objects to be joined together
* @param separator
* used between elements when joining
+ * @deprecated use {@link InternalStringUtils#asString(Method, String)} instead.
*/
public static String join(List elements, String separator)
{
- switch (elements.size())
- {
- case 0:
- return "";
-
- case 1:
- return elements.get(0).toString();
-
- default:
-
- StringBuilder buffer = new StringBuilder();
- boolean first = true;
-
- for (Object o : elements)
- {
- if (!first)
- buffer.append(separator);
-
- String string = String.valueOf(o);
-
- if (string.equals(""))
- string = "(blank)";
-
- buffer.append(string);
-
- first = false;
- }
-
- return buffer.toString();
- }
+ return InternalStringUtils.join(elements, separator);
}
/**
@@ -479,29 +419,21 @@ public class InternalUtils
*
* @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
* empty
+ * @deprecated use {@link InternalStringUtils#joinSorted(Collection)} instead.
*/
public static String joinSorted(Collection elements)
{
- if (elements == null || elements.isEmpty())
- return "(none)";
-
- List<String> list = CollectionFactory.newList();
-
- for (Object o : elements)
- list.add(String.valueOf(o));
-
- Collections.sort(list);
-
- return join(list);
+ return InternalStringUtils.joinSorted(elements);
}
/**
* Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ * @deprecated use {@link InternalStringUtils#isBlank(String)} instead.
*/
public static boolean isBlank(String input)
{
- return input == null || input.length() == 0 || input.trim().length() == 0;
+ return InternalStringUtils.isBlank(input);
}
/**
@@ -518,20 +450,21 @@ public class InternalUtils
return false;
}
+ /**
+ * @deprecated use {@link InternalStringUtils#isNonBlank(String)} instead.
+ */
public static boolean isNonBlank(String input)
{
- return !isBlank(input);
+ return InternalStringUtils.isNonBlank(input);
}
/**
* Capitalizes a string, converting the first character to uppercase.
+ * @deprecated use {@link InternalStringUtils#capitalize(String)} instead.
*/
public static String capitalize(String input)
{
- if (input.length() == 0)
- return input;
-
- return input.substring(0, 1).toUpperCase() + input.substring(1);
+ return InternalStringUtils.capitalize(input);
}
/**
@@ -639,10 +572,11 @@ public class InternalUtils
/**
* Return true if the input string contains the marker for symbols that must be expanded.
+ * @deprecated use {@link InternalStringUtils#containsSymbols(String)} instead.
*/
public static boolean containsSymbols(String input)
{
- return input.contains("${");
+ return InternalStringUtils.containsSymbols(input);
}
/**
@@ -650,16 +584,11 @@ public class InternalUtils
* generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
* expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
* character.
+ * @deprecated use {@link InternalStringUtils#lastTerm(String)} instead.
*/
public static String lastTerm(String input)
{
- assert InternalUtils.isNonBlank(input);
- int dotx = input.lastIndexOf('.');
-
- if (dotx < 0)
- return input;
-
- return input.substring(dotx + 1);
+ return InternalStringUtils.lastTerm(input);
}
/**
@@ -848,18 +777,9 @@ public class InternalUtils
*/
public static AnnotationProvider toAnnotationProvider(final Class element)
{
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationClass.cast(element.getAnnotation(annotationClass));
- }
- };
+ return BeanModelUtils.toAnnotationProvider(element);
}
- ;
-
/**
* @since 5.3
*/
@@ -1484,17 +1404,7 @@ public class InternalUtils
public static AnnotationProvider toAnnotationProvider(final Method element)
{
- if (element == null)
- return NULL_ANNOTATION_PROVIDER;
-
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return element.getAnnotation(annotationClass);
- }
- };
+ return BeanModelUtils.toAnnotationProvider(element);
}
public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,
[02/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
deleted file mode 100644
index 81d1f77..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2006, 2007, 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.ioc;
-
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.services.MasterObjectProvider;
-
-import java.lang.annotation.Annotation;
-
-/**
- * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
- * to objects or object instances available by other means. Services are accessed via service id, or
- * (when appropriate)
- * by just service interface. The Registry itself implements this interface, as does
- * {@link org.apache.tapestry5.ioc.ServiceResources}.
- */
-public interface ObjectLocator
-{
- /**
- * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
- * implements the same
- * interface as the actual service, and is used to instantiate the actual service only as needed
- * (this is
- * transparent to the application).
- *
- * @param <T>
- * @param serviceId unique Service id used to locate the service object (may contain <em>symbols</em>,
- * which
- * will be expanded), case is ignored
- * @param serviceInterface the interface implemented by the service (or an interface extended by the service
- * interface)
- * @return the service instance
- * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
- */
- <T> T getService(String serviceId, Class<T> serviceInterface);
-
- /**
- * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
- * interface (which * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
- * (not the service <em>implementation</em>), which may result in a failure due to extra
- * matches.
- *
- * @param serviceInterface the interface the service implements
- * @return the service's proxy
- * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
- * services directly implement, or extend from, the service interface
- * @see org.apache.tapestry5.ioc.annotations.Marker
- */
- <T> T getService(Class<T> serviceInterface);
-
- /**
- * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
- * interface (which * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
- * (not the service <em>implementation</em>), which may result in a failure due to extra
- * matches. The ability to specify marker annotation types was added in 5.3
- *
- * @param serviceInterface the interface the service implements
- * @param markerTypes Markers used to select a specific service that implements the interface
- * @return the service's proxy
- * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
- * services directly implement, or extend from, the service interface
- * @see org.apache.tapestry5.ioc.annotations.Marker
- * @since 5.3
- */
- <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
-
- /**
- * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
- *
- * @param objectType the type of object to be returned
- * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
- * be
- * obtained, which may be utilized in selecting an appropriate object, use
- * <strong>null</strong> when annotations are not available (in which case, selection
- * will
- * be based only on the object type)
- * @param <T>
- * @return the requested object
- * @see ObjectProvider
- */
- <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider);
-
- /**
- * Autobuilds a class by finding the public constructor with the most parameters. Services and other resources or
- * dependencies will be injected into the parameters of the constructor and into private fields marked with the
- * {@link Inject} annotation. There are two cases: constructing a service implementation, and constructing
- * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
- * just dependencies or objects provided via
- * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
- *
- * @param <T>
- * @param clazz the type of object to instantiate
- * @return the instantiated instance
- * @throws RuntimeException if the autobuild fails
- * @see MasterObjectProvider
- */
- <T> T autobuild(Class<T> clazz);
-
- /**
- * Preferred version of {@link #autobuild(Class)} that tracks the operation using
- * {@link OperationTracker#invoke(String, Invokable)}.
- *
- * @param <T>
- * @param description description used with {@link OperationTracker}
- * @param clazz the type of object to instantiate
- * @return the instantiated instance
- * @throws RuntimeException if the autobuild fails
- * @see MasterObjectProvider
- * @since 5.2.0
- */
- <T> T autobuild(String description, Class<T> clazz);
-
- /**
- * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
- * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
- * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
- * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
- * of autobuilding).
- * <p/>
- * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
- * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
- * (with dependencies).
- *
- * @param <T>
- * @param interfaceClass the interface implemented by the proxy
- * @param implementationClass a concrete class that implements the interface
- * @return a proxy
- * @see #autobuild(Class)
- */
- <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
deleted file mode 100644
index b81c1c5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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.ioc;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Locale;
-
-/**
- * Represents a resource on the server that may be used for server side processing, or may be exposed to the client
- * side. Generally, this represents an abstraction on top of files on the class path and files stored in the web
- * application context.
- * <p/>
- * Resources are often used as map keys; they should be immutable and should implement hashCode() and equals().
- */
-public interface Resource
-{
-
- /**
- * Returns true if the resource exists; if a stream to the content of the file may be opened. A resource exists
- * if {@link #toURL()} returns a non-null value. Starting in release 5.3.4, the result of this is cached.
- * <p/>
- * Starting in 5.4, some "virtual resources", may return true even though {@link #toURL()} returns null.
- *
- * @return true if the resource exists, false if it does not
- */
- boolean exists();
-
-
- /**
- * Returns true if the resource is virtual, meaning this is no underlying file. Many operations are unsupported
- * on virtual resources, including {@link #toURL()}, {@link #forLocale(java.util.Locale)},
- * {@link #withExtension(String)}, {@link #getFile()}, {@link #getFolder()}, {@link #getPath()}}; these
- * operations will throw an {@link java.lang.UnsupportedOperationException}.
- *
- * @since 5.4
- */
- boolean isVirtual();
-
- /**
- * Opens a stream to the content of the resource, or returns null if the resource does not exist. The native
- * input stream supplied by the resource is wrapped in a {@link java.io.BufferedInputStream}.
- *
- * @return an open, buffered stream to the content, if available
- */
- InputStream openStream() throws IOException;
-
- /**
- * Returns the URL for the resource, or null if it does not exist. This value is lazily computed; starting in 5.3.4, subclasses may cache
- * the result. Starting in 5.4, some "virtual resources" may return null.
- */
- URL toURL();
-
- /**
- * Returns a localized version of the resource. May return null if no such resource exists. Starting in release
- * 5.3.4, the result of this method is cached internally.
- */
- Resource forLocale(Locale locale);
-
- /**
- * Returns a Resource based on a relative path, relative to the folder containing the resource. Understands the "."
- * (current folder) and ".." (parent folder) conventions, and treats multiple sequential slashes as a single slash.
- * <p/>
- * Virtual resources (resources fabricated at runtime) return themselves.
- */
- Resource forFile(String relativePath);
-
- /**
- * Returns a new Resource with the extension changed (or, if the resource does not have an extension, the extension
- * is added). The new Resource may not exist (that is, {@link #toURL()} may return null.
- *
- * @param extension
- * to apply to the resource, such as "html" or "properties"
- * @return the new resource
- */
- Resource withExtension(String extension);
-
- /**
- * Returns the portion of the path up to the last forward slash; this is the directory or folder portion of the
- * Resource.
- */
- String getFolder();
-
- /**
- * Returns the file portion of the Resource path, everything that follows the final forward slash.
- * <p/>
- * Starting in 5.4, certain kinds of "virtual resources" may return null here.
- */
- String getFile();
-
- /**
- * Return the path (the combination of folder and file).
- * <p/>
- * Starting in 5.4, certain "virtual resources", may return an arbitrary value here.
- */
- String getPath();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
deleted file mode 100644
index 2e03557..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2008, 2009 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.ioc.annotations;
-
-import java.lang.annotation.*;
-
-
-/**
- * A documentation-only interface placed on service interfaces for services which have an {@linkplain
- * org.apache.tapestry5.ioc.Configuration unordered configuration}, to identify the type of contribution.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesConfiguration
-{
- /**
- * The type of object which may be contributed into the service's configuration.
- */
- Class value();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
deleted file mode 100644
index 716b7c6..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.ioc.internal;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A null implementation of {@link AnnotationProvider}, used when there is not appropriate source of annotations.
- */
-public class NullAnnotationProvider implements AnnotationProvider
-{
- /**
- * Always returns null.
- */
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return null;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
deleted file mode 100644
index 6711b1a..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2006, 2007, 2012 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.ioc.internal.util;
-
-import org.apache.tapestry5.ioc.util.CaseInsensitiveMap;
-import org.apache.tapestry5.ioc.util.Stack;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Static factory methods to ease the creation of new collection types (when using generics). Most of these method
- * leverage the compiler's ability to match generic types by return value. Typical usage (with a static import):
- * <p/>
- * <pre>
- * Map<Foo, Bar> map = newMap();
- * </pre>
- * <p/>
- * <p/>
- * This is a replacement for:
- * <p/>
- * <pre>
- * Map<Foo, Bar> map = new HashMap<Foo, Bar>();
- * </pre>
- */
-public final class CollectionFactory
-{
- /**
- * Constructs and returns a generic {@link HashMap} instance.
- */
- public static <K, V> Map<K, V> newMap()
- {
- return new HashMap<K, V>();
- }
-
- /**
- * Constructs and returns a generic {@link java.util.HashSet} instance.
- */
- public static <T> Set<T> newSet()
- {
- return new HashSet<T>();
- }
-
- /**
- * Contructs a new {@link HashSet} and initializes it using the provided collection.
- */
- public static <T, V extends T> Set<T> newSet(Collection<V> values)
- {
- return new HashSet<T>(values);
- }
-
- public static <T, V extends T> Set<T> newSet(V... values)
- {
- // Was a call to newSet(), but Sun JDK can't handle that. Fucking generics.
- return new HashSet<T>(Arrays.asList(values));
- }
-
- /**
- * Constructs a new {@link java.util.HashMap} instance by copying an existing Map instance.
- */
- public static <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map)
- {
- return new HashMap<K, V>(map);
- }
-
- /**
- * Constructs a new concurrent map, which is safe to access via multiple threads.
- */
- public static <K, V> ConcurrentMap<K, V> newConcurrentMap()
- {
- return new ConcurrentHashMap<K, V>();
- }
-
- /**
- * Contructs and returns a new generic {@link java.util.ArrayList} instance.
- */
- public static <T> List<T> newList()
- {
- return new ArrayList<T>();
- }
-
- /**
- * Creates a new, fully modifiable list from an initial set of elements.
- */
- public static <T, V extends T> List<T> newList(V... elements)
- {
- // Was call to newList(), but Sun JDK can't handle that.
- return new ArrayList<T>(Arrays.asList(elements));
- }
-
- /**
- * Useful for queues.
- */
- public static <T> LinkedList<T> newLinkedList()
- {
- return new LinkedList<T>();
- }
-
- /**
- * Constructs and returns a new {@link java.util.ArrayList} as a copy of the provided collection.
- */
- public static <T, V extends T> List<T> newList(Collection<V> list)
- {
- return new ArrayList<T>(list);
- }
-
- /**
- * Constructs and returns a new {@link java.util.concurrent.CopyOnWriteArrayList}.
- */
- public static <T> List<T> newThreadSafeList()
- {
- return new CopyOnWriteArrayList<T>();
- }
-
- public static <T> Stack<T> newStack()
- {
- return new Stack<T>();
- }
-
- public static <V> Map<String, V> newCaseInsensitiveMap()
- {
- return new CaseInsensitiveMap<V>();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
deleted file mode 100644
index 1a6dd80..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
+++ /dev/null
@@ -1,615 +0,0 @@
-// Copyright 2008, 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.ioc.internal.util;
-
-import java.lang.reflect.*;
-import java.util.LinkedList;
-
-/**
- * Static methods related to the use of JDK 1.5 generics.
- */
-@SuppressWarnings("unchecked")
-public class GenericsUtils
-{
- /**
- * Analyzes the method in the context of containingClass and returns the Class that is represented by
- * the method's generic return type. Any parameter information in the generic return type is lost. If you want
- * to preserve the type parameters of the return type consider using
- * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
- *
- * @param containingClass class which either contains or inherited the method
- * @param method method from which to extract the return type
- * @return the class represented by the methods generic return type, resolved based on the context .
- * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
- * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
- * @see #asClass(java.lang.reflect.Type)
- */
- public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
- {
- return asClass(resolve(method.getGenericReturnType(), containingClass));
- }
-
-
- /**
- * Analyzes the field in the context of containingClass and returns the Class that is represented by
- * the field's generic type. Any parameter information in the generic type is lost, if you want
- * to preserve the type parameters of the return type consider using
- * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
- *
- * @param containingClass class which either contains or inherited the field
- * @param field field from which to extract the type
- * @return the class represented by the field's generic type, resolved based on the containingClass.
- * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
- * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
- * @see #asClass(java.lang.reflect.Type)
- */
- public static Class extractGenericFieldType(Class containingClass, Field field)
- {
- return asClass(resolve(field.getGenericType(), containingClass));
- }
-
- /**
- * Analyzes the method in the context of containingClass and returns the Class that is represented by
- * the method's generic return type. Any parameter information in the generic return type is lost.
- *
- * @param containingType Type which is/represents the class that either contains or inherited the method
- * @param method method from which to extract the generic return type
- * @return the generic type represented by the methods generic return type, resolved based on the containingType.
- * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
- */
- public static Type extractActualType(Type containingType, Method method)
- {
- return resolve(method.getGenericReturnType(), containingType);
- }
-
- /**
- * Analyzes the method in the context of containingClass and returns the Class that is represented by
- * the method's generic return type. Any parameter information in the generic return type is lost.
- *
- * @param containingType Type which is/represents the class that either contains or inherited the field
- * @param field field from which to extract the generic return type
- * @return the generic type represented by the methods generic return type, resolved based on the containingType.
- * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
- */
- public static Type extractActualType(Type containingType, Field field)
- {
- return resolve(field.getGenericType(), containingType);
- }
-
- /**
- * Resolves the type parameter based on the context of the containingType.
- * <p/>
- * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
- * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
- * instance (e.g. List<E>; List<Map<Long, String>>, E would be returned as a ParameterizedType with the raw
- * type Map and type arguments Long and String.
- * <p/>
- *
- * @param type
- * the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
- * @param containingType
- * the type which his
- * @return
- * the type resolved to the best of our ability.
- * @since 5.2.?
- */
- public static Type resolve(final Type type, final Type containingType)
- {
- // The type isn't generic. (String, Long, etc)
- if (type instanceof Class)
- return type;
-
- // List<T>, List<String>, List<T extends Number>
- if (type instanceof ParameterizedType)
- return resolve((ParameterizedType) type, containingType);
-
- // T[], List<String>[], List<T>[]
- if (type instanceof GenericArrayType)
- return resolve((GenericArrayType) type, containingType);
-
- // List<? extends T>, List<? extends Object & Comparable & Serializable>
- if (type instanceof WildcardType)
- return resolve((WildcardType) type, containingType);
-
- // T
- if (type instanceof TypeVariable)
- return resolve((TypeVariable) type, containingType);
-
- // I'm leaning towards an exception here.
- return type;
- }
-
-
- /**
- * Determines if the suspected super type is assignable from the suspected sub type.
- *
- * @param suspectedSuperType
- * e.g. GenericDAO<Pet, String>
- * @param suspectedSubType
- * e.g. PetDAO extends GenericDAO<Pet,String>
- * @return
- * true if (sourceType)targetClass is a valid cast
- */
- public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
- {
- final Class suspectedSuperClass = asClass(suspectedSuperType);
- final Class suspectedSubClass = asClass(suspectedSubType);
-
- // The raw types need to be compatible.
- if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
- {
- return false;
- }
-
- // From this point we know that the raw types are assignable.
- // We need to figure out what the generic parameters in the targetClass are
- // as they pertain to the sourceType.
-
- if (suspectedSuperType instanceof WildcardType)
- {
- // ? extends Number
- // needs to match all the bounds (there will only be upper bounds or lower bounds
- for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
- {
- if (!isAssignableFrom(t, suspectedSubType)) return false;
- }
- for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
- {
- if (!isAssignableFrom(suspectedSubType, t)) return false;
- }
- return true;
- }
-
- Type curType = suspectedSubType;
- Class curClass;
-
- while (curType != null && !curType.equals(Object.class))
- {
- curClass = asClass(curType);
-
- if (curClass.equals(suspectedSuperClass))
- {
- final Type resolved = resolve(curType, suspectedSubType);
-
- if (suspectedSuperType instanceof Class)
- {
- if ( resolved instanceof Class )
- return suspectedSuperType.equals(resolved);
-
- // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
- // types default to Object so they must be a match.
- // e.g. Pair p = new StringLongPair();
- // Pair p = new Pair<? extends Number, String>
-
- return true;
- }
-
- if (suspectedSuperType instanceof ParameterizedType)
- {
- if (resolved instanceof ParameterizedType)
- {
- final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
- final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
- if (type1Arguments.length != type2Arguments.length) return false;
-
- for (int i = 0; i < type1Arguments.length; ++i)
- {
- if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
- }
- return true;
- }
- }
- else if (suspectedSuperType instanceof GenericArrayType)
- {
- if (resolved instanceof GenericArrayType)
- {
- return isAssignableFrom(
- ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
- ((GenericArrayType) resolved).getGenericComponentType()
- );
- }
- }
-
- return false;
- }
-
- final Type[] types = curClass.getGenericInterfaces();
- for (Type t : types)
- {
- final Type resolved = resolve(t, suspectedSubType);
- if (isAssignableFrom(suspectedSuperType, resolved))
- return true;
- }
-
- curType = curClass.getGenericSuperclass();
- }
- return false;
- }
-
- /**
- * Get the class represented by the reflected type.
- * This method is lossy; You cannot recover the type information from the class that is returned.
- * <p/>
- * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
- * is lost.
- * <p/>
- * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
- * then {@code Object} is returned.
- *
- * @param actualType
- * a Class, ParameterizedType, GenericArrayType
- * @return the un-parameterized class associated with the type.
- */
- public static Class asClass(Type actualType)
- {
- if (actualType instanceof Class) return (Class) actualType;
-
- if (actualType instanceof ParameterizedType)
- {
- final Type rawType = ((ParameterizedType) actualType).getRawType();
- // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
- // some other Type. We'll assume it's a Class.
- // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
- return (Class) rawType;
- }
-
- if (actualType instanceof GenericArrayType)
- {
- final Type type = ((GenericArrayType) actualType).getGenericComponentType();
- return Array.newInstance(asClass(type), 0).getClass();
- }
-
- if (actualType instanceof TypeVariable)
- {
- // Support for List<T extends Number>
- // There is always at least one bound. If no bound is specified in the source then it will be Object.class
- return asClass(((TypeVariable) actualType).getBounds()[0]);
- }
-
- if (actualType instanceof WildcardType)
- {
- final WildcardType wildcardType = (WildcardType) actualType;
- final Type[] bounds = wildcardType.getLowerBounds();
- if (bounds != null && bounds.length > 0)
- {
- return asClass(bounds[0]);
- }
- // If there is no lower bounds then the only thing that makes sense is Object.
- return Object.class;
- }
-
- throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
- }
-
- /**
- * Convert the type into a string. The string representation approximates the code that would be used to define the
- * type.
- *
- * @param type - the type.
- * @return a string representation of the type, similar to how it was declared.
- */
- public static String toString(Type type)
- {
- if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
- if ( type instanceof WildcardType ) return toString((WildcardType)type);
- if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
- if ( type instanceof Class )
- {
- final Class theClass = (Class) type;
- return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
- }
- return type.toString();
- }
-
- /**
- * Method to resolve a TypeVariable to its most
- * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
- * <p/>
- * <p/>
- * How to resolve a TypeVariable:<br/>
- * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
- * given may or may not be reifiable; it may be another TypeVariable for instance.
- * <p/>
- * Consider <br/>
- * <i>class Pair>A,B> { A getA(){...}; ...}</i><br/>
- * <i>class StringLongPair extends Pair>String, Long> { }</i><br/>
- * <p/>
- * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
- * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
- * <p/>
- * To get to the Type provided by StringLongPair you access the generics information by calling
- * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
- * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
- * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
- * <p/>
- * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
- * the class. When a class implements a generic interface it must provide types for the interface and any generic
- * methods implemented from the interface will be re-defined by the class with its generic type variables.
- *
- * @param typeVariable - the type variable to resolve.
- * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
- * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
- * declaration and the containingType.
- */
- private static Type resolve(TypeVariable typeVariable, Type containingType)
- {
- // The generic declaration is either a Class, Method or Constructor
- final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
-
- if (!(genericDeclaration instanceof Class))
- {
- // It's a method or constructor. The best we can do here is try to resolve the bounds
- // e.g. <T extends E> T getT(T param){} where E is defined by the class.
- final Type bounds0 = typeVariable.getBounds()[0];
- return resolve(bounds0, containingType);
- }
-
- final Class typeVariableOwner = (Class) genericDeclaration;
-
- // find the typeOwner in the containingType's hierarchy
- final LinkedList<Type> stack = new LinkedList<Type>();
-
- // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
- // containingType and not the super class.
- if (containingType instanceof ParameterizedType)
- {
- stack.add(containingType);
- }
-
- Class theClass = asClass(containingType);
- Type genericSuperclass = theClass.getGenericSuperclass();
- while (genericSuperclass != null && // true for interfaces with no superclass
- !theClass.equals(Object.class) &&
- !theClass.equals(typeVariableOwner))
- {
- stack.addFirst(genericSuperclass);
- theClass = asClass(genericSuperclass);
- genericSuperclass = theClass.getGenericSuperclass();
- }
-
- int i = getTypeVariableIndex(typeVariable);
- Type resolved = typeVariable;
- for (Type t : stack)
- {
- if (t instanceof ParameterizedType)
- {
- resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
- if (resolved instanceof Class) return resolved;
- if (resolved instanceof TypeVariable)
- {
- // Need to look at the next class in the hierarchy
- i = getTypeVariableIndex((TypeVariable) resolved);
- continue;
- }
- return resolve(resolved, containingType);
- }
- }
-
- // the only way we get here is if resolved is still a TypeVariable, otherwise an
- // exception is thrown or a value is returned.
- return ((TypeVariable) resolved).getBounds()[0];
- }
-
- /**
- * @param type - something like List<T>[] or List<? extends T>[] or T[]
- * @param containingType - the shallowest type in the hierarchy where type is defined.
- * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
- */
- private static GenericArrayType resolve(GenericArrayType type, Type containingType)
- {
- final Type componentType = type.getGenericComponentType();
-
- if (!(componentType instanceof Class))
- {
- final Type resolved = resolve(componentType, containingType);
- return create(resolved);
- }
-
- return type;
- }
-
- /**
- * @param type - something like List<T>, List<T extends Number>
- * @param containingType - the shallowest type in the hierarchy where type is defined.
- * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
- */
- private static ParameterizedType resolve(ParameterizedType type, Type containingType)
- {
- // Use a copy because we're going to modify it.
- final Type[] types = type.getActualTypeArguments().clone();
-
- boolean modified = resolve(types, containingType);
- return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
- }
-
- /**
- * @param type - something like List<? super T>, List<<? extends T>, List<? extends T & Comparable<? super T>>
- * @param containingType - the shallowest type in the hierarchy where type is defined.
- * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
- */
- private static WildcardType resolve(WildcardType type, Type containingType)
- {
- // Use a copy because we're going to modify them.
- final Type[] upper = type.getUpperBounds().clone();
- final Type[] lower = type.getLowerBounds().clone();
-
- boolean modified = resolve(upper, containingType);
- modified = modified || resolve(lower, containingType);
-
- return modified ? create(upper, lower) : type;
- }
-
- /**
- * @param types - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
- * @param containingType - the shallowest type in the hierarchy where type is defined.
- * @return true if any of the types were resolved.
- */
- private static boolean resolve(Type[] types, Type containingType)
- {
- boolean modified = false;
- for (int i = 0; i < types.length; ++i)
- {
- Type t = types[i];
- if (!(t instanceof Class))
- {
- modified = true;
- final Type resolved = resolve(t, containingType);
- if (!resolved.equals(t))
- {
- types[i] = resolved;
- modified = true;
- }
- }
- }
- return modified;
- }
-
- /**
- * @param rawType - the un-parameterized type.
- * @param ownerType - the outer class or null if the class is not defined within another class.
- * @param typeArguments - type arguments.
- * @return a copy of the type with the typeArguments replaced.
- */
- static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
- {
- return new ParameterizedType()
- {
- @Override
- public Type[] getActualTypeArguments()
- {
- return typeArguments;
- }
-
- @Override
- public Type getRawType()
- {
- return rawType;
- }
-
- @Override
- public Type getOwnerType()
- {
- return ownerType;
- }
-
- @Override
- public String toString()
- {
- return GenericsUtils.toString(this);
- }
- };
- }
-
- static GenericArrayType create(final Type componentType)
- {
- return new GenericArrayType()
- {
- @Override
- public Type getGenericComponentType()
- {
- return componentType;
- }
-
- @Override
- public String toString()
- {
- return GenericsUtils.toString(this);
- }
- };
- }
-
- /**
- * @param upperBounds - e.g. ? extends Number
- * @param lowerBounds - e.g. ? super Long
- * @return An new copy of the type with the upper and lower bounds replaced.
- */
- static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
- {
-
- return new WildcardType()
- {
- @Override
- public Type[] getUpperBounds()
- {
- return upperBounds;
- }
-
- @Override
- public Type[] getLowerBounds()
- {
- return lowerBounds;
- }
-
- @Override
- public String toString()
- {
- return GenericsUtils.toString(this);
- }
- };
- }
-
- static String toString(ParameterizedType pt)
- {
- String s = toString(pt.getActualTypeArguments());
- return String.format("%s<%s>", toString(pt.getRawType()), s);
- }
-
- static String toString(GenericArrayType gat)
- {
- return String.format("%s[]", toString(gat.getGenericComponentType()));
- }
-
- static String toString(WildcardType wt)
- {
- final boolean isSuper = wt.getLowerBounds().length > 0;
- return String.format("? %s %s",
- isSuper ? "super" : "extends",
- isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
- }
-
- static String toString(Type[] types)
- {
- StringBuilder sb = new StringBuilder();
- for ( Type t : types )
- {
- sb.append(toString(t)).append(", ");
- }
- return sb.substring(0, sb.length() - 2);// drop last ,
- }
-
- /**
- * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
- * the actual type.
- *
- * @param typeVariable - the type variable in question.
- * @return the index of the type variable in its declaring class/method/constructor's type parameters.
- */
- private static int getTypeVariableIndex(final TypeVariable typeVariable)
- {
- // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
- final String typeVarName = typeVariable.getName();
- final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
- for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
- {
- // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
- if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
- return typeArgumentIndex;
- }
-
- // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
- throw new RuntimeException(
- String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
deleted file mode 100644
index ef217cb..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2006 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.ioc.internal.util;
-
-import org.apache.tapestry5.ioc.Locatable;
-import org.apache.tapestry5.ioc.Location;
-
-/**
- * Exception class used as a replacement for {@link java.lang.RuntimeException} when the exception is related to a
- * particular location.
- */
-public class TapestryException extends RuntimeException implements Locatable
-{
- private static final long serialVersionUID = 6396903640977182682L;
-
- private transient final Location location;
-
- /**
- * @param message a message (may be null)
- * @param location implements {@link Location} or {@link Locatable}
- * @param cause if not null, the root cause of the exception
- */
- public TapestryException(String message, Object location, Throwable cause)
- {
- this(message, InternalUtils.locationOf(location), cause);
- }
-
- /**
- * @param message a message (may be null)
- * @param cause if not null, the root cause of the exception, also used to set the location
- */
- public TapestryException(String message, Throwable cause)
- {
- this(message, cause, cause);
- }
-
- /**
- * @param message a message (may be null)
- * @param location location to associated with the exception, or null if not known
- * @param cause if not null, the root cause of the exception
- */
- public TapestryException(String message, Location location, Throwable cause)
- {
- super(message, cause);
-
- this.location = location;
- }
-
- @Override
- public Location getLocation()
- {
- return location;
- }
-
- @Override
- public String toString()
- {
- if (location == null) return super.toString();
-
- return String.format("%s [at %s]", super.toString(), location);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
deleted file mode 100644
index 6159ed3..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2006, 2007, 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.ioc.services;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-
-/**
- * Organizes all {@link org.apache.tapestry5.ioc.services.PropertyAdapter}s for a particular class.
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
- * <p/>
- * When accessing properties by name, the case of the name is ignored.
- */
-public interface ClassPropertyAdapter
-{
- /**
- * Returns the names of all properties, sorted into alphabetic order. This includes true properties
- * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
- */
- List<String> getPropertyNames();
-
- /**
- * Returns the type of bean this adapter provides properties for.
- */
- Class getBeanType();
-
- /**
- * Returns the property adapter with the given name, or null if no such adapter exists.
- *
- * @param name of the property (case is ignored)
- */
- PropertyAdapter getPropertyAdapter(String name);
-
- /**
- * Reads the value of a property.
- *
- * @param instance the object to read a value from
- * @param propertyName the name of the property to read (case is ignored)
- * @throws UnsupportedOperationException if the property is write only
- * @throws IllegalArgumentException if property does not exist
- */
- Object get(Object instance, String propertyName);
-
- /**
- * Updates the value of a property.
- *
- * @param instance the object to update
- * @param propertyName the name of the property to update (case is ignored)
- * @throws UnsupportedOperationException if the property is read only
- * @throws IllegalArgumentException if property does not exist
- */
- void set(Object instance, String propertyName, Object value);
-
- /**
- * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
- *
- * @param instance the object to read a value from
- * @param propertyName the name of the property to read (case is ignored)
- * @param annotationClass the type of annotation to return
- *
- * @throws IllegalArgumentException if property does not exist
- *
- * @since 5.4
- */
- Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
deleted file mode 100644
index b7a4cc8..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2006 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.ioc.services;
-
-/**
- * Responsible for converting from one type to another. This is used primarily around component parameters.
- *
- * @param <S> the source type (input)
- * @param <T> the target type (output)
- */
-public interface Coercion<S, T>
-{
- /**
- * Converts an input value.
- *
- * @param input the input value
- */
- T coerce(S input);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
deleted file mode 100644
index 746de1e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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.ioc.services;
-
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-/**
- * An immutable object that represents a mapping from one type to another. This is also the contribution type when
- * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
- * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
- * describe
- * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
- * coercions).
- *
- * @param <S>
- * source (input) type
- * @param <T>
- * target (output) type
- */
-public final class CoercionTuple<S, T>
-{
- private final Class<S> sourceType;
-
- private final Class<T> targetType;
-
- private final Coercion<S, T> coercion;
-
- /**
- * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
- */
- private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
- {
- private final Coercion<WS, WT> coercion;
-
- public CoercionWrapper(Coercion<WS, WT> coercion)
- {
- this.coercion = coercion;
- }
-
- @Override
- public WT coerce(WS input)
- {
- return coercion.coerce(input);
- }
-
- @Override
- public String toString()
- {
- return String.format("%s --> %s", convert(sourceType), convert(targetType));
- }
- }
-
- private String convert(Class type)
- {
- if (Void.class.equals(type))
- return "null";
-
- String name = PlasticUtils.toTypeName(type);
-
- int dotx = name.lastIndexOf('.');
-
- // Strip off a package name of "java.lang"
-
- if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
- return name.substring(dotx + 1);
-
- return name;
- }
-
- /**
- * Standard constructor, which defaults wrap to true.
- */
- public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
- {
- this(sourceType, targetType, coercion, true);
- }
-
- /**
- * Convenience constructor to help with generics.
- *
- * @since 5.2.0
- */
- public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
- {
- return new CoercionTuple<S, T>(sourceType, targetType, coercion);
- }
-
- /**
- * Internal-use constructor.
- *
- * @param sourceType
- * the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
- * @param targetType
- * the target (or output) type of the coercion
- * @param coercion
- * the object that performs the coercion
- * @param wrap
- * if true, the coercion is wrapped to provide a useful toString()
- */
- @SuppressWarnings("unchecked")
- public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
- {
- assert sourceType != null;
- assert targetType != null;
- assert coercion != null;
-
- this.sourceType = PlasticUtils.toWrapperType(sourceType);
- this.targetType = PlasticUtils.toWrapperType(targetType);
- this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
- }
-
- @Override
- public String toString()
- {
- return coercion.toString();
- }
-
- public Coercion<S, T> getCoercion()
- {
- return coercion;
- }
-
- public Class<S> getSourceType()
- {
- return sourceType;
- }
-
- public Class<T> getTargetType()
- {
- return targetType;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
deleted file mode 100644
index ae542c5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2006, 2010, 2013 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.ioc.services;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
- * <p>
- * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
- * is a name conflict, the true property will be favored over the field access.
- */
-public interface PropertyAccess
-{
- /**
- * Reads the value of a property.
- *
- * @throws UnsupportedOperationException
- * if the property is write only
- * @throws IllegalArgumentException
- * if property does not exist
- */
- Object get(Object instance, String propertyName);
-
- /**
- * Updates the value of a property.
- *
- * @throws UnsupportedOperationException
- * if the property is read only
- * @throws IllegalArgumentException
- * if property does not exist
- */
- void set(Object instance, String propertyName, Object value);
-
- /**
- * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
- * A convenience over invoking {@link #getAdapter(Object)}.{@link ClassPropertyAdapter#getPropertyAdapter(String)}.{@link PropertyAdapter#getAnnotation(Class)}
- *
- * @param instance the object to read a value from
- * @param propertyName the name of the property to read (case is ignored)
- * @param annotationClass the type of annotation to return
- * @throws IllegalArgumentException
- * if property does not exist
- *
- * @since 5.4
- */
- Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
-
- /**
- * Returns the adapter for a particular object instance. A convienience over invoking {@link #getAdapter(Class)}.
- */
- ClassPropertyAdapter getAdapter(Object instance);
-
- /**
- * Returns the adapter used to access properties within the indicated class.
- */
- ClassPropertyAdapter getAdapter(Class forClass);
-
- /**
- * Discards all stored property access information, discarding all created class adapters.
- */
- void clearCache();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
deleted file mode 100644
index 947535e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2006, 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.ioc.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-/**
- * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
- * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
- * by the underlying field (when the property name matches the field name).
- * <p/>
- * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
- *
- * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
- */
-@SuppressWarnings("unchecked")
-public interface PropertyAdapter extends AnnotationProvider
-{
- /**
- * Returns the name of the property (or public field).
- */
- String getName();
-
- /**
- * Returns true if the property is readable (i.e., has a getter method or is a public field).
- */
- boolean isRead();
-
- /**
- * Returns the method used to read the property, or null if the property is not readable (or is a public field).
- */
- public Method getReadMethod();
-
- /**
- * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
- */
- boolean isUpdate();
-
- /**
- * Returns the method used to update the property, or null if the property is not writeable (or a public field).
- */
- public Method getWriteMethod();
-
- /**
- * Reads the property value.
- *
- * @param instance to read from
- * @throws UnsupportedOperationException if the property is write only
- */
- Object get(Object instance);
-
- /**
- * Updates the property value. The provided value must not be null if the property type is primitive, and must
- * otherwise be of the proper type.
- *
- * @param instance to update
- * @param value new value for the property
- * @throws UnsupportedOperationException if the property is read only
- */
- void set(Object instance, Object value);
-
- /**
- * Returns the type of the property.
- */
- Class getType();
-
- /**
- * Returns true if the return type of the read method is not the same as the property type. This can occur when the
- * property has been defined using generics, in which case, the method's type may be Object when the property type
- * is something more specific. This method is primarily used when generating runtime code related to the property.
- */
- boolean isCastRequired();
-
- /**
- * Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
- * properties defined by the same class.
- */
- ClassPropertyAdapter getClassAdapter();
-
- /**
- * Returns the type of bean to which this property belongs. This is the same as
- * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
- */
- Class getBeanType();
-
- /**
- * Returns true if the property is actually a public field (possibly, a public static field).
- *
- * @since 5.2
- */
- boolean isField();
-
- /**
- * Returns the field if the property is a public field or null if the property is accessed via the read method.
- *
- * @since 5.2
- */
- Field getField();
-
- /**
- * The class in which the property (or public field) is defined.
- *
- * @since 5.2
- */
- Class getDeclaringClass();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
deleted file mode 100644
index ec8eaad..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2006, 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.ioc.services;
-
-import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
-
-/**
- * Makes use of {@link org.apache.tapestry5.ioc.services.Coercion}s to convert between an input value (of some specific
- * type) and a desired output type. Smart about coercing, even if it requires multiple coercion steps (i.e., via an
- * intermediate type, such as String).
- */
-@UsesConfiguration(CoercionTuple.class)
-public interface TypeCoercer
-{
- /**
- * Performs a coercion from an input type to a desired output type. When the target type is a primitive, the actual
- * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
- * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
- * the search are cached.
- * <p/>
- * The TypeCoercer also caches the results of a coercion search.
- *
- * @param <S>
- * source type (input)
- * @param <T>
- * target type (output)
- * @param input
- * @param targetType
- * defines the target type
- * @return the coerced value
- * @throws RuntimeException
- * if the input can not be coerced
- */
- <S, T> T coerce(S input, Class<T> targetType);
-
- /**
- * Given a source and target type, computes the coercion that will be used.
- * <p>
- * Note: holding the returned coercion past the time when {@linkplain #clearCache() the cache is cleared} can cause
- * a memory leak, especially in the context of live reloading (wherein holding a reference to a single class make
- * keep an entire ClassLoader from being reclaimed).
- *
- * @since 5.2.0
- * @param <S>
- * source type (input)
- * @param <T>
- * target type (output)
- * @param sourceType
- * type to coerce from
- * @param targetType
- * defines the target type
- * @return the coercion that will ultimately be used
- */
- <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType);
-
- /**
- * Used primarily inside test suites, this method performs the same steps as {@link #coerce(Object, Class)}, but
- * returns a string describing the series of coercions, such as "Object --> String --> Long --> Integer".
- *
- * @param <S>
- * source type (input)
- * @param <T>
- * target type (output)
- * @param sourceType
- * the source coercion type (use void.class for coercions from null)
- * @param targetType
- * defines the target type
- * @return a string identifying the series of coercions, or the empty string if no coercion is necessary
- */
- <S, T> String explain(Class<S> sourceType, Class<T> targetType);
-
- /**
- * Clears cached information stored by the TypeCoercer.
- */
- void clearCache();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
deleted file mode 100644
index c4c5c6d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.ioc.util;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-/**
- * Used (as part of a {@link UnknownValueException} to identify what available values
- * are present.
- *
- * @since 5.2.0
- */
-public class AvailableValues
-{
- private final String valueType;
-
- private final List<String> values;
-
- /**
- * @param valueType
- * a word or phrase that describes what the values are such as "component types" or "service ids"
- *@param values
- * a set of objects defining the values; the values will be converted to strings and sorted into
- * ascending order
- */
- public AvailableValues(String valueType, Collection<?> values)
- {
- this.valueType = valueType;
- this.values = sortValues(values);
- }
-
- public AvailableValues(String valueType, Map<?, ?> map)
- {
- this(valueType, map.keySet());
- }
-
- private static List<String> sortValues(Collection<?> values)
- {
- List<String> result = CollectionFactory.newList();
-
- for (Object v : values)
- {
- result.add(String.valueOf(v));
- }
-
- Collections.sort(result);
-
- return Collections.unmodifiableList(result);
- }
-
- /** The type of value, i.e., "component types" or "service ids". */
- public String getValueType()
- {
- return valueType;
- }
-
- /** The values, as strings, in sorted order. */
- public List<String> getValues()
- {
- return values;
- }
-
- @Override
- public String toString()
- {
- return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
deleted file mode 100644
index f5aff7e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
+++ /dev/null
@@ -1,499 +0,0 @@
-// 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.ioc.util;
-
-import java.io.Serializable;
-import java.util.*;
-
-/**
- * An mapped collection where the keys are always strings and access to values is case-insensitive. The case of keys in
- * the map is <em>maintained</em>, but on any access to a key (directly or indirectly), all key comparisons are
- * performed in a case-insensitive manner. The map implementation is intended to support a reasonably finite number
- * (dozens or hundreds, not thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of
- * entries rather than hash bucket. It is also geared towards a largely static map, one that is created and then used
- * without modification.
- *
- * @param <V> the type of value stored
- */
-public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
-{
- private static final long serialVersionUID = 3362718337611953298L;
-
- private static final int NULL_HASH = Integer.MIN_VALUE;
-
- private static final int DEFAULT_SIZE = 20;
-
- private static class CIMEntry<V> implements Map.Entry<String, V>, Serializable
- {
- private static final long serialVersionUID = 6713986085221148350L;
-
- private String key;
-
- private final int hashCode;
-
- V value;
-
- public CIMEntry(final String key, final int hashCode, V value)
- {
- this.key = key;
- this.hashCode = hashCode;
- this.value = value;
- }
-
- @Override
- public String getKey()
- {
- return key;
- }
-
- @Override
- public V getValue()
- {
- return value;
- }
-
- @Override
- public V setValue(V value)
- {
- V result = this.value;
-
- this.value = value;
-
- return result;
- }
-
- /**
- * Returns true if both keys are null, or if the provided key is the same as, or case-insensitively equal to,
- * the entrie's key.
- *
- * @param key to compare against
- * @return true if equal
- */
- @SuppressWarnings({ "StringEquality" })
- boolean matches(String key)
- {
- return key == this.key || (key != null && key.equalsIgnoreCase(this.key));
- }
-
- boolean valueMatches(Object value)
- {
- return value == this.value || (value != null && value.equals(this.value));
- }
- }
-
- private class EntrySetIterator implements Iterator
- {
- int expectedModCount = modCount;
-
- int index;
-
- int current = -1;
-
- @Override
- public boolean hasNext()
- {
- return index < size;
- }
-
- @Override
- public Object next()
- {
- check();
-
- if (index >= size) throw new NoSuchElementException();
-
- current = index++;
-
- return entries[current];
- }
-
- @Override
- public void remove()
- {
- check();
-
- if (current < 0) throw new NoSuchElementException();
-
- new Position(current, true).remove();
-
- expectedModCount = modCount;
- }
-
- private void check()
- {
- if (expectedModCount != modCount) throw new ConcurrentModificationException();
- }
- }
-
- @SuppressWarnings("unchecked")
- private class EntrySet extends AbstractSet
- {
- @Override
- public Iterator iterator()
- {
- return new EntrySetIterator();
- }
-
- @Override
- public int size()
- {
- return size;
- }
-
- @Override
- public void clear()
- {
- CaseInsensitiveMap.this.clear();
- }
-
- @Override
- public boolean contains(Object o)
- {
- if (!(o instanceof Map.Entry)) return false;
-
- Map.Entry e = (Map.Entry) o;
-
- Position position = select(e.getKey());
-
- return position.isFound() && position.entry().valueMatches(e.getValue());
- }
-
- @Override
- public boolean remove(Object o)
- {
- if (!(o instanceof Map.Entry)) return false;
-
- Map.Entry e = (Map.Entry) o;
-
- Position position = select(e.getKey());
-
- if (position.isFound() && position.entry().valueMatches(e.getValue()))
- {
- position.remove();
- return true;
- }
-
- return false;
- }
-
- }
-
- private class Position
- {
- private final int cursor;
-
- private final boolean found;
-
- Position(int cursor, boolean found)
- {
- this.cursor = cursor;
- this.found = found;
- }
-
- boolean isFound()
- {
- return found;
- }
-
- CIMEntry<V> entry()
- {
- return entries[cursor];
- }
-
- V get()
- {
- return found ? entries[cursor].value : null;
- }
-
- V remove()
- {
- if (!found) return null;
-
- V result = entries[cursor].value;
-
- // Remove the entry by shifting everything else down.
-
- System.arraycopy(entries, cursor + 1, entries, cursor, size - cursor - 1);
-
- // We shifted down, leaving one (now duplicate) entry behind.
-
- entries[--size] = null;
-
- // A structural change for sure
-
- modCount++;
-
- return result;
- }
-
- @SuppressWarnings("unchecked")
- V put(String key, int hashCode, V newValue)
- {
- if (found)
- {
- CIMEntry<V> e = entries[cursor];
-
- V result = e.value;
-
- // Not a structural change, so no change to modCount
-
- // Update the key (to maintain case). By definition, the hash code
- // will not change.
-
- e.key = key;
- e.value = newValue;
-
- return result;
- }
-
- // Not found, we're going to add it.
-
- int newSize = size + 1;
-
- if (newSize == entries.length)
- {
- // Time to expand!
-
- int newCapacity = (size * 3) / 2 + 1;
-
- CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
-
- System.arraycopy(entries, 0, newEntries, 0, cursor);
-
- System.arraycopy(entries, cursor, newEntries, cursor + 1, size - cursor);
-
- entries = newEntries;
- }
- else
- {
- // Open up a space for the new entry
-
- System.arraycopy(entries, cursor, entries, cursor + 1, size - cursor);
- }
-
- CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, newValue);
- entries[cursor] = newEntry;
-
- size++;
-
- // This is definately a structural change
-
- modCount++;
-
- return null;
- }
-
- }
-
- // The list of entries. This is kept sorted by hash code. In some cases, there may be different
- // keys with the same hash code in adjacent indexes.
- private CIMEntry<V>[] entries;
-
- private int size = 0;
-
- // Used by iterators to check for concurrent modifications
-
- private transient int modCount = 0;
-
- private transient Set<Map.Entry<String, V>> entrySet;
-
- public CaseInsensitiveMap()
- {
- this(DEFAULT_SIZE);
- }
-
- @SuppressWarnings("unchecked")
- public CaseInsensitiveMap(int size)
- {
- entries = new CIMEntry[Math.max(size, 3)];
- }
-
- public CaseInsensitiveMap(Map<String, ? extends V> map)
- {
- this(map.size());
-
- for (Map.Entry<String, ? extends V> entry : map.entrySet())
- {
- put(entry.getKey(), entry.getValue());
- }
- }
-
- @Override
- public void clear()
- {
- for (int i = 0; i < size; i++)
- entries[i] = null;
-
- size = 0;
- modCount++;
- }
-
- @Override
- public boolean isEmpty()
- {
- return size == 0;
- }
-
- @Override
- public int size()
- {
- return size;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public V put(String key, V value)
- {
- int hashCode = caseInsenitiveHashCode(key);
-
- return select(key, hashCode).put(key, hashCode, value);
- }
-
- @Override
- public boolean containsKey(Object key)
- {
- return select(key).isFound();
- }
-
- @Override
- public V get(Object key)
- {
- return select(key).get();
- }
-
- @Override
- public V remove(Object key)
- {
- return select(key).remove();
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Set<Map.Entry<String, V>> entrySet()
- {
- if (entrySet == null) entrySet = new EntrySet();
-
- return entrySet;
- }
-
- private Position select(Object key)
- {
- if (key == null || key instanceof String)
- {
- String keyString = (String) key;
- return select(keyString, caseInsenitiveHashCode(keyString));
- }
-
- return new Position(0, false);
- }
-
- /**
- * Searches the elements for the index of the indicated key and (case insensitive) hash code. Sets the _cursor and
- * _found attributes.
- */
- private Position select(String key, int hashCode)
- {
- if (size == 0) return new Position(0, false);
-
- int low = 0;
- int high = size - 1;
-
- int cursor;
-
- while (low <= high)
- {
- cursor = (low + high) >> 1;
-
- CIMEntry e = entries[cursor];
-
- if (e.hashCode < hashCode)
- {
- low = cursor + 1;
- continue;
- }
-
- if (e.hashCode > hashCode)
- {
- high = cursor - 1;
- continue;
- }
-
- return tunePosition(key, hashCode, cursor);
- }
-
- return new Position(low, false);
- }
-
- /**
- * select() has located a matching hashCode, but there's an outlying possibility that multiple keys share the same
- * hashCode. Backup the cursor until we get to locate the initial hashCode match, then march forward until the key
- * is located, or the hashCode stops matching.
- *
- * @param key
- * @param hashCode
- */
- private Position tunePosition(String key, int hashCode, int cursor)
- {
- boolean found = false;
-
- while (cursor > 0)
- {
- if (entries[cursor - 1].hashCode != hashCode) break;
-
- cursor--;
- }
-
- while (true)
- {
- if (entries[cursor].matches(key))
- {
- found = true;
- break;
- }
-
- // Advance to the next entry.
-
- cursor++;
-
- // If out of entries,
- if (cursor >= size || entries[cursor].hashCode != hashCode) break;
- }
-
- return new Position(cursor, found);
- }
-
- static int caseInsenitiveHashCode(String input)
- {
- if (input == null) return NULL_HASH;
-
- int length = input.length();
- int hash = 0;
-
- // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
- // changes its implementation. Let's hope this is reasonably fast.
-
- for (int i = 0; i < length; i++)
- {
- int ch = input.charAt(i);
-
- int caselessCh = Character.toLowerCase(ch);
-
- hash = 31 * hash + caselessCh;
- }
-
- return hash;
- }
-
-}
[04/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
new file mode 100644
index 0000000..b9b4aa3
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
@@ -0,0 +1,33 @@
+// Copyright 2006, 2007, 2012 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.services;
+
+/**
+ * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files,
+ * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external
+ * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as
+ * necessary).
+ *
+ * @see org.apache.tapestry5.services.InvalidationEventHub
+ * @since 5.1.0.0
+ * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead
+ */
+public interface InvalidationListener
+{
+ /**
+ * Invoked to indicate that some object is invalid. The receiver should clear its cache.
+ */
+ void objectWasInvalidated();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 6397777..593c3a4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,5 +4,5 @@ include "tapestry-beanvalidator", "tapestry-jpa", "tapestry-kaptcha"
include "tapestry-javadoc", "quickstart", "tapestry-clojure", "tapestry-mongodb"
include "tapestry-test-data", 'tapestry-internal-test', "tapestry-ioc-junit"
include "tapestry-webresources", "tapestry-runner", "tapestry-test-constants"
-include "tapestry-ioc-jcache"
+include "tapestry-ioc-jcache", "beanmodel", "commons"
// include "tapestry-cdi"
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index c16cd48..584200a 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -18,6 +18,7 @@ configurations {
dependencies {
compile project(':tapestry-ioc')
compile project(':tapestry-json')
+ compile project(':beanmodel')
provided project(":tapestry-test")
provided project(":tapestry-test-constants")
@@ -26,11 +27,6 @@ dependencies {
compile "commons-codec:commons-codec:1.5"
- // 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"
- }
-
// Antlr3 tool path used with the antlr3 task
antlr3 "org.antlr:antlr:3.5.2"
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
deleted file mode 100644
index 3dbb0c0..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
deleted file mode 100644
index 839d70f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java b/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
deleted file mode 100644
index 0a60fd7..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java b/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
deleted file mode 100644
index 6095fb9..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
deleted file mode 100644
index 315b372..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
deleted file mode 100644
index 26eb309..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ /dev/null
@@ -1,289 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
deleted file mode 100644
index 703ce44..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
deleted file mode 100644
index 4dbfb2d..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
deleted file mode 100644
index 1242031..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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);
- }
-}
[02/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
deleted file mode 100644
index 81d1f77..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2006, 2007, 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.ioc;
-
-import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.services.MasterObjectProvider;
-
-import java.lang.annotation.Annotation;
-
-/**
- * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
- * to objects or object instances available by other means. Services are accessed via service id, or
- * (when appropriate)
- * by just service interface. The Registry itself implements this interface, as does
- * {@link org.apache.tapestry5.ioc.ServiceResources}.
- */
-public interface ObjectLocator
-{
- /**
- * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
- * implements the same
- * interface as the actual service, and is used to instantiate the actual service only as needed
- * (this is
- * transparent to the application).
- *
- * @param <T>
- * @param serviceId unique Service id used to locate the service object (may contain <em>symbols</em>,
- * which
- * will be expanded), case is ignored
- * @param serviceInterface the interface implemented by the service (or an interface extended by the service
- * interface)
- * @return the service instance
- * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
- */
- <T> T getService(String serviceId, Class<T> serviceInterface);
-
- /**
- * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
- * interface (which * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
- * (not the service <em>implementation</em>), which may result in a failure due to extra
- * matches.
- *
- * @param serviceInterface the interface the service implements
- * @return the service's proxy
- * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
- * services directly implement, or extend from, the service interface
- * @see org.apache.tapestry5.ioc.annotations.Marker
- */
- <T> T getService(Class<T> serviceInterface);
-
- /**
- * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
- * interface (which * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
- * (not the service <em>implementation</em>), which may result in a failure due to extra
- * matches. The ability to specify marker annotation types was added in 5.3
- *
- * @param serviceInterface the interface the service implements
- * @param markerTypes Markers used to select a specific service that implements the interface
- * @return the service's proxy
- * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
- * services directly implement, or extend from, the service interface
- * @see org.apache.tapestry5.ioc.annotations.Marker
- * @since 5.3
- */
- <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
-
- /**
- * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
- *
- * @param objectType the type of object to be returned
- * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
- * be
- * obtained, which may be utilized in selecting an appropriate object, use
- * <strong>null</strong> when annotations are not available (in which case, selection
- * will
- * be based only on the object type)
- * @param <T>
- * @return the requested object
- * @see ObjectProvider
- */
- <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider);
-
- /**
- * Autobuilds a class by finding the public constructor with the most parameters. Services and other resources or
- * dependencies will be injected into the parameters of the constructor and into private fields marked with the
- * {@link Inject} annotation. There are two cases: constructing a service implementation, and constructing
- * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
- * just dependencies or objects provided via
- * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
- *
- * @param <T>
- * @param clazz the type of object to instantiate
- * @return the instantiated instance
- * @throws RuntimeException if the autobuild fails
- * @see MasterObjectProvider
- */
- <T> T autobuild(Class<T> clazz);
-
- /**
- * Preferred version of {@link #autobuild(Class)} that tracks the operation using
- * {@link OperationTracker#invoke(String, Invokable)}.
- *
- * @param <T>
- * @param description description used with {@link OperationTracker}
- * @param clazz the type of object to instantiate
- * @return the instantiated instance
- * @throws RuntimeException if the autobuild fails
- * @see MasterObjectProvider
- * @since 5.2.0
- */
- <T> T autobuild(String description, Class<T> clazz);
-
- /**
- * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
- * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
- * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
- * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
- * of autobuilding).
- * <p/>
- * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
- * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
- * (with dependencies).
- *
- * @param <T>
- * @param interfaceClass the interface implemented by the proxy
- * @param implementationClass a concrete class that implements the interface
- * @return a proxy
- * @see #autobuild(Class)
- */
- <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
deleted file mode 100644
index b81c1c5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Resource.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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.ioc;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Locale;
-
-/**
- * Represents a resource on the server that may be used for server side processing, or may be exposed to the client
- * side. Generally, this represents an abstraction on top of files on the class path and files stored in the web
- * application context.
- * <p/>
- * Resources are often used as map keys; they should be immutable and should implement hashCode() and equals().
- */
-public interface Resource
-{
-
- /**
- * Returns true if the resource exists; if a stream to the content of the file may be opened. A resource exists
- * if {@link #toURL()} returns a non-null value. Starting in release 5.3.4, the result of this is cached.
- * <p/>
- * Starting in 5.4, some "virtual resources", may return true even though {@link #toURL()} returns null.
- *
- * @return true if the resource exists, false if it does not
- */
- boolean exists();
-
-
- /**
- * Returns true if the resource is virtual, meaning this is no underlying file. Many operations are unsupported
- * on virtual resources, including {@link #toURL()}, {@link #forLocale(java.util.Locale)},
- * {@link #withExtension(String)}, {@link #getFile()}, {@link #getFolder()}, {@link #getPath()}}; these
- * operations will throw an {@link java.lang.UnsupportedOperationException}.
- *
- * @since 5.4
- */
- boolean isVirtual();
-
- /**
- * Opens a stream to the content of the resource, or returns null if the resource does not exist. The native
- * input stream supplied by the resource is wrapped in a {@link java.io.BufferedInputStream}.
- *
- * @return an open, buffered stream to the content, if available
- */
- InputStream openStream() throws IOException;
-
- /**
- * Returns the URL for the resource, or null if it does not exist. This value is lazily computed; starting in 5.3.4, subclasses may cache
- * the result. Starting in 5.4, some "virtual resources" may return null.
- */
- URL toURL();
-
- /**
- * Returns a localized version of the resource. May return null if no such resource exists. Starting in release
- * 5.3.4, the result of this method is cached internally.
- */
- Resource forLocale(Locale locale);
-
- /**
- * Returns a Resource based on a relative path, relative to the folder containing the resource. Understands the "."
- * (current folder) and ".." (parent folder) conventions, and treats multiple sequential slashes as a single slash.
- * <p/>
- * Virtual resources (resources fabricated at runtime) return themselves.
- */
- Resource forFile(String relativePath);
-
- /**
- * Returns a new Resource with the extension changed (or, if the resource does not have an extension, the extension
- * is added). The new Resource may not exist (that is, {@link #toURL()} may return null.
- *
- * @param extension
- * to apply to the resource, such as "html" or "properties"
- * @return the new resource
- */
- Resource withExtension(String extension);
-
- /**
- * Returns the portion of the path up to the last forward slash; this is the directory or folder portion of the
- * Resource.
- */
- String getFolder();
-
- /**
- * Returns the file portion of the Resource path, everything that follows the final forward slash.
- * <p/>
- * Starting in 5.4, certain kinds of "virtual resources" may return null here.
- */
- String getFile();
-
- /**
- * Return the path (the combination of folder and file).
- * <p/>
- * Starting in 5.4, certain "virtual resources", may return an arbitrary value here.
- */
- String getPath();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
deleted file mode 100644
index 2e03557..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesConfiguration.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2008, 2009 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.ioc.annotations;
-
-import java.lang.annotation.*;
-
-
-/**
- * A documentation-only interface placed on service interfaces for services which have an {@linkplain
- * org.apache.tapestry5.ioc.Configuration unordered configuration}, to identify the type of contribution.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesConfiguration
-{
- /**
- * The type of object which may be contributed into the service's configuration.
- */
- Class value();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
deleted file mode 100644
index 716b7c6..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.ioc.internal;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A null implementation of {@link AnnotationProvider}, used when there is not appropriate source of annotations.
- */
-public class NullAnnotationProvider implements AnnotationProvider
-{
- /**
- * Always returns null.
- */
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return null;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
deleted file mode 100644
index 6711b1a..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2006, 2007, 2012 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.ioc.internal.util;
-
-import org.apache.tapestry5.ioc.util.CaseInsensitiveMap;
-import org.apache.tapestry5.ioc.util.Stack;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Static factory methods to ease the creation of new collection types (when using generics). Most of these method
- * leverage the compiler's ability to match generic types by return value. Typical usage (with a static import):
- * <p/>
- * <pre>
- * Map<Foo, Bar> map = newMap();
- * </pre>
- * <p/>
- * <p/>
- * This is a replacement for:
- * <p/>
- * <pre>
- * Map<Foo, Bar> map = new HashMap<Foo, Bar>();
- * </pre>
- */
-public final class CollectionFactory
-{
- /**
- * Constructs and returns a generic {@link HashMap} instance.
- */
- public static <K, V> Map<K, V> newMap()
- {
- return new HashMap<K, V>();
- }
-
- /**
- * Constructs and returns a generic {@link java.util.HashSet} instance.
- */
- public static <T> Set<T> newSet()
- {
- return new HashSet<T>();
- }
-
- /**
- * Contructs a new {@link HashSet} and initializes it using the provided collection.
- */
- public static <T, V extends T> Set<T> newSet(Collection<V> values)
- {
- return new HashSet<T>(values);
- }
-
- public static <T, V extends T> Set<T> newSet(V... values)
- {
- // Was a call to newSet(), but Sun JDK can't handle that. Fucking generics.
- return new HashSet<T>(Arrays.asList(values));
- }
-
- /**
- * Constructs a new {@link java.util.HashMap} instance by copying an existing Map instance.
- */
- public static <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map)
- {
- return new HashMap<K, V>(map);
- }
-
- /**
- * Constructs a new concurrent map, which is safe to access via multiple threads.
- */
- public static <K, V> ConcurrentMap<K, V> newConcurrentMap()
- {
- return new ConcurrentHashMap<K, V>();
- }
-
- /**
- * Contructs and returns a new generic {@link java.util.ArrayList} instance.
- */
- public static <T> List<T> newList()
- {
- return new ArrayList<T>();
- }
-
- /**
- * Creates a new, fully modifiable list from an initial set of elements.
- */
- public static <T, V extends T> List<T> newList(V... elements)
- {
- // Was call to newList(), but Sun JDK can't handle that.
- return new ArrayList<T>(Arrays.asList(elements));
- }
-
- /**
- * Useful for queues.
- */
- public static <T> LinkedList<T> newLinkedList()
- {
- return new LinkedList<T>();
- }
-
- /**
- * Constructs and returns a new {@link java.util.ArrayList} as a copy of the provided collection.
- */
- public static <T, V extends T> List<T> newList(Collection<V> list)
- {
- return new ArrayList<T>(list);
- }
-
- /**
- * Constructs and returns a new {@link java.util.concurrent.CopyOnWriteArrayList}.
- */
- public static <T> List<T> newThreadSafeList()
- {
- return new CopyOnWriteArrayList<T>();
- }
-
- public static <T> Stack<T> newStack()
- {
- return new Stack<T>();
- }
-
- public static <V> Map<String, V> newCaseInsensitiveMap()
- {
- return new CaseInsensitiveMap<V>();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
deleted file mode 100644
index 1a6dd80..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
+++ /dev/null
@@ -1,615 +0,0 @@
-// Copyright 2008, 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.ioc.internal.util;
-
-import java.lang.reflect.*;
-import java.util.LinkedList;
-
-/**
- * Static methods related to the use of JDK 1.5 generics.
- */
-@SuppressWarnings("unchecked")
-public class GenericsUtils
-{
- /**
- * Analyzes the method in the context of containingClass and returns the Class that is represented by
- * the method's generic return type. Any parameter information in the generic return type is lost. If you want
- * to preserve the type parameters of the return type consider using
- * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
- *
- * @param containingClass class which either contains or inherited the method
- * @param method method from which to extract the return type
- * @return the class represented by the methods generic return type, resolved based on the context .
- * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
- * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
- * @see #asClass(java.lang.reflect.Type)
- */
- public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
- {
- return asClass(resolve(method.getGenericReturnType(), containingClass));
- }
-
-
- /**
- * Analyzes the field in the context of containingClass and returns the Class that is represented by
- * the field's generic type. Any parameter information in the generic type is lost, if you want
- * to preserve the type parameters of the return type consider using
- * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
- *
- * @param containingClass class which either contains or inherited the field
- * @param field field from which to extract the type
- * @return the class represented by the field's generic type, resolved based on the containingClass.
- * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
- * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
- * @see #asClass(java.lang.reflect.Type)
- */
- public static Class extractGenericFieldType(Class containingClass, Field field)
- {
- return asClass(resolve(field.getGenericType(), containingClass));
- }
-
- /**
- * Analyzes the method in the context of containingClass and returns the Class that is represented by
- * the method's generic return type. Any parameter information in the generic return type is lost.
- *
- * @param containingType Type which is/represents the class that either contains or inherited the method
- * @param method method from which to extract the generic return type
- * @return the generic type represented by the methods generic return type, resolved based on the containingType.
- * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
- */
- public static Type extractActualType(Type containingType, Method method)
- {
- return resolve(method.getGenericReturnType(), containingType);
- }
-
- /**
- * Analyzes the method in the context of containingClass and returns the Class that is represented by
- * the method's generic return type. Any parameter information in the generic return type is lost.
- *
- * @param containingType Type which is/represents the class that either contains or inherited the field
- * @param field field from which to extract the generic return type
- * @return the generic type represented by the methods generic return type, resolved based on the containingType.
- * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
- */
- public static Type extractActualType(Type containingType, Field field)
- {
- return resolve(field.getGenericType(), containingType);
- }
-
- /**
- * Resolves the type parameter based on the context of the containingType.
- * <p/>
- * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
- * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
- * instance (e.g. List<E>; List<Map<Long, String>>, E would be returned as a ParameterizedType with the raw
- * type Map and type arguments Long and String.
- * <p/>
- *
- * @param type
- * the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
- * @param containingType
- * the type which his
- * @return
- * the type resolved to the best of our ability.
- * @since 5.2.?
- */
- public static Type resolve(final Type type, final Type containingType)
- {
- // The type isn't generic. (String, Long, etc)
- if (type instanceof Class)
- return type;
-
- // List<T>, List<String>, List<T extends Number>
- if (type instanceof ParameterizedType)
- return resolve((ParameterizedType) type, containingType);
-
- // T[], List<String>[], List<T>[]
- if (type instanceof GenericArrayType)
- return resolve((GenericArrayType) type, containingType);
-
- // List<? extends T>, List<? extends Object & Comparable & Serializable>
- if (type instanceof WildcardType)
- return resolve((WildcardType) type, containingType);
-
- // T
- if (type instanceof TypeVariable)
- return resolve((TypeVariable) type, containingType);
-
- // I'm leaning towards an exception here.
- return type;
- }
-
-
- /**
- * Determines if the suspected super type is assignable from the suspected sub type.
- *
- * @param suspectedSuperType
- * e.g. GenericDAO<Pet, String>
- * @param suspectedSubType
- * e.g. PetDAO extends GenericDAO<Pet,String>
- * @return
- * true if (sourceType)targetClass is a valid cast
- */
- public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
- {
- final Class suspectedSuperClass = asClass(suspectedSuperType);
- final Class suspectedSubClass = asClass(suspectedSubType);
-
- // The raw types need to be compatible.
- if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
- {
- return false;
- }
-
- // From this point we know that the raw types are assignable.
- // We need to figure out what the generic parameters in the targetClass are
- // as they pertain to the sourceType.
-
- if (suspectedSuperType instanceof WildcardType)
- {
- // ? extends Number
- // needs to match all the bounds (there will only be upper bounds or lower bounds
- for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
- {
- if (!isAssignableFrom(t, suspectedSubType)) return false;
- }
- for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
- {
- if (!isAssignableFrom(suspectedSubType, t)) return false;
- }
- return true;
- }
-
- Type curType = suspectedSubType;
- Class curClass;
-
- while (curType != null && !curType.equals(Object.class))
- {
- curClass = asClass(curType);
-
- if (curClass.equals(suspectedSuperClass))
- {
- final Type resolved = resolve(curType, suspectedSubType);
-
- if (suspectedSuperType instanceof Class)
- {
- if ( resolved instanceof Class )
- return suspectedSuperType.equals(resolved);
-
- // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
- // types default to Object so they must be a match.
- // e.g. Pair p = new StringLongPair();
- // Pair p = new Pair<? extends Number, String>
-
- return true;
- }
-
- if (suspectedSuperType instanceof ParameterizedType)
- {
- if (resolved instanceof ParameterizedType)
- {
- final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
- final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
- if (type1Arguments.length != type2Arguments.length) return false;
-
- for (int i = 0; i < type1Arguments.length; ++i)
- {
- if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
- }
- return true;
- }
- }
- else if (suspectedSuperType instanceof GenericArrayType)
- {
- if (resolved instanceof GenericArrayType)
- {
- return isAssignableFrom(
- ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
- ((GenericArrayType) resolved).getGenericComponentType()
- );
- }
- }
-
- return false;
- }
-
- final Type[] types = curClass.getGenericInterfaces();
- for (Type t : types)
- {
- final Type resolved = resolve(t, suspectedSubType);
- if (isAssignableFrom(suspectedSuperType, resolved))
- return true;
- }
-
- curType = curClass.getGenericSuperclass();
- }
- return false;
- }
-
- /**
- * Get the class represented by the reflected type.
- * This method is lossy; You cannot recover the type information from the class that is returned.
- * <p/>
- * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
- * is lost.
- * <p/>
- * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
- * then {@code Object} is returned.
- *
- * @param actualType
- * a Class, ParameterizedType, GenericArrayType
- * @return the un-parameterized class associated with the type.
- */
- public static Class asClass(Type actualType)
- {
- if (actualType instanceof Class) return (Class) actualType;
-
- if (actualType instanceof ParameterizedType)
- {
- final Type rawType = ((ParameterizedType) actualType).getRawType();
- // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
- // some other Type. We'll assume it's a Class.
- // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
- return (Class) rawType;
- }
-
- if (actualType instanceof GenericArrayType)
- {
- final Type type = ((GenericArrayType) actualType).getGenericComponentType();
- return Array.newInstance(asClass(type), 0).getClass();
- }
-
- if (actualType instanceof TypeVariable)
- {
- // Support for List<T extends Number>
- // There is always at least one bound. If no bound is specified in the source then it will be Object.class
- return asClass(((TypeVariable) actualType).getBounds()[0]);
- }
-
- if (actualType instanceof WildcardType)
- {
- final WildcardType wildcardType = (WildcardType) actualType;
- final Type[] bounds = wildcardType.getLowerBounds();
- if (bounds != null && bounds.length > 0)
- {
- return asClass(bounds[0]);
- }
- // If there is no lower bounds then the only thing that makes sense is Object.
- return Object.class;
- }
-
- throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
- }
-
- /**
- * Convert the type into a string. The string representation approximates the code that would be used to define the
- * type.
- *
- * @param type - the type.
- * @return a string representation of the type, similar to how it was declared.
- */
- public static String toString(Type type)
- {
- if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
- if ( type instanceof WildcardType ) return toString((WildcardType)type);
- if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
- if ( type instanceof Class )
- {
- final Class theClass = (Class) type;
- return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
- }
- return type.toString();
- }
-
- /**
- * Method to resolve a TypeVariable to its most
- * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
- * <p/>
- * <p/>
- * How to resolve a TypeVariable:<br/>
- * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
- * given may or may not be reifiable; it may be another TypeVariable for instance.
- * <p/>
- * Consider <br/>
- * <i>class Pair>A,B> { A getA(){...}; ...}</i><br/>
- * <i>class StringLongPair extends Pair>String, Long> { }</i><br/>
- * <p/>
- * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
- * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
- * <p/>
- * To get to the Type provided by StringLongPair you access the generics information by calling
- * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
- * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
- * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
- * <p/>
- * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
- * the class. When a class implements a generic interface it must provide types for the interface and any generic
- * methods implemented from the interface will be re-defined by the class with its generic type variables.
- *
- * @param typeVariable - the type variable to resolve.
- * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
- * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
- * declaration and the containingType.
- */
- private static Type resolve(TypeVariable typeVariable, Type containingType)
- {
- // The generic declaration is either a Class, Method or Constructor
- final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
-
- if (!(genericDeclaration instanceof Class))
- {
- // It's a method or constructor. The best we can do here is try to resolve the bounds
- // e.g. <T extends E> T getT(T param){} where E is defined by the class.
- final Type bounds0 = typeVariable.getBounds()[0];
- return resolve(bounds0, containingType);
- }
-
- final Class typeVariableOwner = (Class) genericDeclaration;
-
- // find the typeOwner in the containingType's hierarchy
- final LinkedList<Type> stack = new LinkedList<Type>();
-
- // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
- // containingType and not the super class.
- if (containingType instanceof ParameterizedType)
- {
- stack.add(containingType);
- }
-
- Class theClass = asClass(containingType);
- Type genericSuperclass = theClass.getGenericSuperclass();
- while (genericSuperclass != null && // true for interfaces with no superclass
- !theClass.equals(Object.class) &&
- !theClass.equals(typeVariableOwner))
- {
- stack.addFirst(genericSuperclass);
- theClass = asClass(genericSuperclass);
- genericSuperclass = theClass.getGenericSuperclass();
- }
-
- int i = getTypeVariableIndex(typeVariable);
- Type resolved = typeVariable;
- for (Type t : stack)
- {
- if (t instanceof ParameterizedType)
- {
- resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
- if (resolved instanceof Class) return resolved;
- if (resolved instanceof TypeVariable)
- {
- // Need to look at the next class in the hierarchy
- i = getTypeVariableIndex((TypeVariable) resolved);
- continue;
- }
- return resolve(resolved, containingType);
- }
- }
-
- // the only way we get here is if resolved is still a TypeVariable, otherwise an
- // exception is thrown or a value is returned.
- return ((TypeVariable) resolved).getBounds()[0];
- }
-
- /**
- * @param type - something like List<T>[] or List<? extends T>[] or T[]
- * @param containingType - the shallowest type in the hierarchy where type is defined.
- * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
- */
- private static GenericArrayType resolve(GenericArrayType type, Type containingType)
- {
- final Type componentType = type.getGenericComponentType();
-
- if (!(componentType instanceof Class))
- {
- final Type resolved = resolve(componentType, containingType);
- return create(resolved);
- }
-
- return type;
- }
-
- /**
- * @param type - something like List<T>, List<T extends Number>
- * @param containingType - the shallowest type in the hierarchy where type is defined.
- * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
- */
- private static ParameterizedType resolve(ParameterizedType type, Type containingType)
- {
- // Use a copy because we're going to modify it.
- final Type[] types = type.getActualTypeArguments().clone();
-
- boolean modified = resolve(types, containingType);
- return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
- }
-
- /**
- * @param type - something like List<? super T>, List<<? extends T>, List<? extends T & Comparable<? super T>>
- * @param containingType - the shallowest type in the hierarchy where type is defined.
- * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
- */
- private static WildcardType resolve(WildcardType type, Type containingType)
- {
- // Use a copy because we're going to modify them.
- final Type[] upper = type.getUpperBounds().clone();
- final Type[] lower = type.getLowerBounds().clone();
-
- boolean modified = resolve(upper, containingType);
- modified = modified || resolve(lower, containingType);
-
- return modified ? create(upper, lower) : type;
- }
-
- /**
- * @param types - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
- * @param containingType - the shallowest type in the hierarchy where type is defined.
- * @return true if any of the types were resolved.
- */
- private static boolean resolve(Type[] types, Type containingType)
- {
- boolean modified = false;
- for (int i = 0; i < types.length; ++i)
- {
- Type t = types[i];
- if (!(t instanceof Class))
- {
- modified = true;
- final Type resolved = resolve(t, containingType);
- if (!resolved.equals(t))
- {
- types[i] = resolved;
- modified = true;
- }
- }
- }
- return modified;
- }
-
- /**
- * @param rawType - the un-parameterized type.
- * @param ownerType - the outer class or null if the class is not defined within another class.
- * @param typeArguments - type arguments.
- * @return a copy of the type with the typeArguments replaced.
- */
- static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
- {
- return new ParameterizedType()
- {
- @Override
- public Type[] getActualTypeArguments()
- {
- return typeArguments;
- }
-
- @Override
- public Type getRawType()
- {
- return rawType;
- }
-
- @Override
- public Type getOwnerType()
- {
- return ownerType;
- }
-
- @Override
- public String toString()
- {
- return GenericsUtils.toString(this);
- }
- };
- }
-
- static GenericArrayType create(final Type componentType)
- {
- return new GenericArrayType()
- {
- @Override
- public Type getGenericComponentType()
- {
- return componentType;
- }
-
- @Override
- public String toString()
- {
- return GenericsUtils.toString(this);
- }
- };
- }
-
- /**
- * @param upperBounds - e.g. ? extends Number
- * @param lowerBounds - e.g. ? super Long
- * @return An new copy of the type with the upper and lower bounds replaced.
- */
- static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
- {
-
- return new WildcardType()
- {
- @Override
- public Type[] getUpperBounds()
- {
- return upperBounds;
- }
-
- @Override
- public Type[] getLowerBounds()
- {
- return lowerBounds;
- }
-
- @Override
- public String toString()
- {
- return GenericsUtils.toString(this);
- }
- };
- }
-
- static String toString(ParameterizedType pt)
- {
- String s = toString(pt.getActualTypeArguments());
- return String.format("%s<%s>", toString(pt.getRawType()), s);
- }
-
- static String toString(GenericArrayType gat)
- {
- return String.format("%s[]", toString(gat.getGenericComponentType()));
- }
-
- static String toString(WildcardType wt)
- {
- final boolean isSuper = wt.getLowerBounds().length > 0;
- return String.format("? %s %s",
- isSuper ? "super" : "extends",
- isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
- }
-
- static String toString(Type[] types)
- {
- StringBuilder sb = new StringBuilder();
- for ( Type t : types )
- {
- sb.append(toString(t)).append(", ");
- }
- return sb.substring(0, sb.length() - 2);// drop last ,
- }
-
- /**
- * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
- * the actual type.
- *
- * @param typeVariable - the type variable in question.
- * @return the index of the type variable in its declaring class/method/constructor's type parameters.
- */
- private static int getTypeVariableIndex(final TypeVariable typeVariable)
- {
- // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
- final String typeVarName = typeVariable.getName();
- final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
- for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
- {
- // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
- if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
- return typeArgumentIndex;
- }
-
- // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
- throw new RuntimeException(
- String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
deleted file mode 100644
index ef217cb..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2006 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.ioc.internal.util;
-
-import org.apache.tapestry5.ioc.Locatable;
-import org.apache.tapestry5.ioc.Location;
-
-/**
- * Exception class used as a replacement for {@link java.lang.RuntimeException} when the exception is related to a
- * particular location.
- */
-public class TapestryException extends RuntimeException implements Locatable
-{
- private static final long serialVersionUID = 6396903640977182682L;
-
- private transient final Location location;
-
- /**
- * @param message a message (may be null)
- * @param location implements {@link Location} or {@link Locatable}
- * @param cause if not null, the root cause of the exception
- */
- public TapestryException(String message, Object location, Throwable cause)
- {
- this(message, InternalUtils.locationOf(location), cause);
- }
-
- /**
- * @param message a message (may be null)
- * @param cause if not null, the root cause of the exception, also used to set the location
- */
- public TapestryException(String message, Throwable cause)
- {
- this(message, cause, cause);
- }
-
- /**
- * @param message a message (may be null)
- * @param location location to associated with the exception, or null if not known
- * @param cause if not null, the root cause of the exception
- */
- public TapestryException(String message, Location location, Throwable cause)
- {
- super(message, cause);
-
- this.location = location;
- }
-
- @Override
- public Location getLocation()
- {
- return location;
- }
-
- @Override
- public String toString()
- {
- if (location == null) return super.toString();
-
- return String.format("%s [at %s]", super.toString(), location);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
deleted file mode 100644
index 6159ed3..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2006, 2007, 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.ioc.services;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-
-/**
- * Organizes all {@link org.apache.tapestry5.ioc.services.PropertyAdapter}s for a particular class.
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
- * <p/>
- * When accessing properties by name, the case of the name is ignored.
- */
-public interface ClassPropertyAdapter
-{
- /**
- * Returns the names of all properties, sorted into alphabetic order. This includes true properties
- * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
- */
- List<String> getPropertyNames();
-
- /**
- * Returns the type of bean this adapter provides properties for.
- */
- Class getBeanType();
-
- /**
- * Returns the property adapter with the given name, or null if no such adapter exists.
- *
- * @param name of the property (case is ignored)
- */
- PropertyAdapter getPropertyAdapter(String name);
-
- /**
- * Reads the value of a property.
- *
- * @param instance the object to read a value from
- * @param propertyName the name of the property to read (case is ignored)
- * @throws UnsupportedOperationException if the property is write only
- * @throws IllegalArgumentException if property does not exist
- */
- Object get(Object instance, String propertyName);
-
- /**
- * Updates the value of a property.
- *
- * @param instance the object to update
- * @param propertyName the name of the property to update (case is ignored)
- * @throws UnsupportedOperationException if the property is read only
- * @throws IllegalArgumentException if property does not exist
- */
- void set(Object instance, String propertyName, Object value);
-
- /**
- * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
- *
- * @param instance the object to read a value from
- * @param propertyName the name of the property to read (case is ignored)
- * @param annotationClass the type of annotation to return
- *
- * @throws IllegalArgumentException if property does not exist
- *
- * @since 5.4
- */
- Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
deleted file mode 100644
index b7a4cc8..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2006 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.ioc.services;
-
-/**
- * Responsible for converting from one type to another. This is used primarily around component parameters.
- *
- * @param <S> the source type (input)
- * @param <T> the target type (output)
- */
-public interface Coercion<S, T>
-{
- /**
- * Converts an input value.
- *
- * @param input the input value
- */
- T coerce(S input);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
deleted file mode 100644
index 746de1e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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.ioc.services;
-
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-/**
- * An immutable object that represents a mapping from one type to another. This is also the contribution type when
- * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
- * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
- * describe
- * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
- * coercions).
- *
- * @param <S>
- * source (input) type
- * @param <T>
- * target (output) type
- */
-public final class CoercionTuple<S, T>
-{
- private final Class<S> sourceType;
-
- private final Class<T> targetType;
-
- private final Coercion<S, T> coercion;
-
- /**
- * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
- */
- private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
- {
- private final Coercion<WS, WT> coercion;
-
- public CoercionWrapper(Coercion<WS, WT> coercion)
- {
- this.coercion = coercion;
- }
-
- @Override
- public WT coerce(WS input)
- {
- return coercion.coerce(input);
- }
-
- @Override
- public String toString()
- {
- return String.format("%s --> %s", convert(sourceType), convert(targetType));
- }
- }
-
- private String convert(Class type)
- {
- if (Void.class.equals(type))
- return "null";
-
- String name = PlasticUtils.toTypeName(type);
-
- int dotx = name.lastIndexOf('.');
-
- // Strip off a package name of "java.lang"
-
- if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
- return name.substring(dotx + 1);
-
- return name;
- }
-
- /**
- * Standard constructor, which defaults wrap to true.
- */
- public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
- {
- this(sourceType, targetType, coercion, true);
- }
-
- /**
- * Convenience constructor to help with generics.
- *
- * @since 5.2.0
- */
- public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
- {
- return new CoercionTuple<S, T>(sourceType, targetType, coercion);
- }
-
- /**
- * Internal-use constructor.
- *
- * @param sourceType
- * the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
- * @param targetType
- * the target (or output) type of the coercion
- * @param coercion
- * the object that performs the coercion
- * @param wrap
- * if true, the coercion is wrapped to provide a useful toString()
- */
- @SuppressWarnings("unchecked")
- public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
- {
- assert sourceType != null;
- assert targetType != null;
- assert coercion != null;
-
- this.sourceType = PlasticUtils.toWrapperType(sourceType);
- this.targetType = PlasticUtils.toWrapperType(targetType);
- this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
- }
-
- @Override
- public String toString()
- {
- return coercion.toString();
- }
-
- public Coercion<S, T> getCoercion()
- {
- return coercion;
- }
-
- public Class<S> getSourceType()
- {
- return sourceType;
- }
-
- public Class<T> getTargetType()
- {
- return targetType;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
deleted file mode 100644
index ae542c5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2006, 2010, 2013 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.ioc.services;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
- * <p/>
- * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
- * <p>
- * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
- * is a name conflict, the true property will be favored over the field access.
- */
-public interface PropertyAccess
-{
- /**
- * Reads the value of a property.
- *
- * @throws UnsupportedOperationException
- * if the property is write only
- * @throws IllegalArgumentException
- * if property does not exist
- */
- Object get(Object instance, String propertyName);
-
- /**
- * Updates the value of a property.
- *
- * @throws UnsupportedOperationException
- * if the property is read only
- * @throws IllegalArgumentException
- * if property does not exist
- */
- void set(Object instance, String propertyName, Object value);
-
- /**
- * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
- * A convenience over invoking {@link #getAdapter(Object)}.{@link ClassPropertyAdapter#getPropertyAdapter(String)}.{@link PropertyAdapter#getAnnotation(Class)}
- *
- * @param instance the object to read a value from
- * @param propertyName the name of the property to read (case is ignored)
- * @param annotationClass the type of annotation to return
- * @throws IllegalArgumentException
- * if property does not exist
- *
- * @since 5.4
- */
- Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
-
- /**
- * Returns the adapter for a particular object instance. A convienience over invoking {@link #getAdapter(Class)}.
- */
- ClassPropertyAdapter getAdapter(Object instance);
-
- /**
- * Returns the adapter used to access properties within the indicated class.
- */
- ClassPropertyAdapter getAdapter(Class forClass);
-
- /**
- * Discards all stored property access information, discarding all created class adapters.
- */
- void clearCache();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
deleted file mode 100644
index 947535e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2006, 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.ioc.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-/**
- * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
- * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
- * by the underlying field (when the property name matches the field name).
- * <p/>
- * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
- *
- * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
- */
-@SuppressWarnings("unchecked")
-public interface PropertyAdapter extends AnnotationProvider
-{
- /**
- * Returns the name of the property (or public field).
- */
- String getName();
-
- /**
- * Returns true if the property is readable (i.e., has a getter method or is a public field).
- */
- boolean isRead();
-
- /**
- * Returns the method used to read the property, or null if the property is not readable (or is a public field).
- */
- public Method getReadMethod();
-
- /**
- * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
- */
- boolean isUpdate();
-
- /**
- * Returns the method used to update the property, or null if the property is not writeable (or a public field).
- */
- public Method getWriteMethod();
-
- /**
- * Reads the property value.
- *
- * @param instance to read from
- * @throws UnsupportedOperationException if the property is write only
- */
- Object get(Object instance);
-
- /**
- * Updates the property value. The provided value must not be null if the property type is primitive, and must
- * otherwise be of the proper type.
- *
- * @param instance to update
- * @param value new value for the property
- * @throws UnsupportedOperationException if the property is read only
- */
- void set(Object instance, Object value);
-
- /**
- * Returns the type of the property.
- */
- Class getType();
-
- /**
- * Returns true if the return type of the read method is not the same as the property type. This can occur when the
- * property has been defined using generics, in which case, the method's type may be Object when the property type
- * is something more specific. This method is primarily used when generating runtime code related to the property.
- */
- boolean isCastRequired();
-
- /**
- * Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
- * properties defined by the same class.
- */
- ClassPropertyAdapter getClassAdapter();
-
- /**
- * Returns the type of bean to which this property belongs. This is the same as
- * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
- */
- Class getBeanType();
-
- /**
- * Returns true if the property is actually a public field (possibly, a public static field).
- *
- * @since 5.2
- */
- boolean isField();
-
- /**
- * Returns the field if the property is a public field or null if the property is accessed via the read method.
- *
- * @since 5.2
- */
- Field getField();
-
- /**
- * The class in which the property (or public field) is defined.
- *
- * @since 5.2
- */
- Class getDeclaringClass();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
deleted file mode 100644
index ec8eaad..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2006, 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.ioc.services;
-
-import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
-
-/**
- * Makes use of {@link org.apache.tapestry5.ioc.services.Coercion}s to convert between an input value (of some specific
- * type) and a desired output type. Smart about coercing, even if it requires multiple coercion steps (i.e., via an
- * intermediate type, such as String).
- */
-@UsesConfiguration(CoercionTuple.class)
-public interface TypeCoercer
-{
- /**
- * Performs a coercion from an input type to a desired output type. When the target type is a primitive, the actual
- * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
- * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
- * the search are cached.
- * <p/>
- * The TypeCoercer also caches the results of a coercion search.
- *
- * @param <S>
- * source type (input)
- * @param <T>
- * target type (output)
- * @param input
- * @param targetType
- * defines the target type
- * @return the coerced value
- * @throws RuntimeException
- * if the input can not be coerced
- */
- <S, T> T coerce(S input, Class<T> targetType);
-
- /**
- * Given a source and target type, computes the coercion that will be used.
- * <p>
- * Note: holding the returned coercion past the time when {@linkplain #clearCache() the cache is cleared} can cause
- * a memory leak, especially in the context of live reloading (wherein holding a reference to a single class make
- * keep an entire ClassLoader from being reclaimed).
- *
- * @since 5.2.0
- * @param <S>
- * source type (input)
- * @param <T>
- * target type (output)
- * @param sourceType
- * type to coerce from
- * @param targetType
- * defines the target type
- * @return the coercion that will ultimately be used
- */
- <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType);
-
- /**
- * Used primarily inside test suites, this method performs the same steps as {@link #coerce(Object, Class)}, but
- * returns a string describing the series of coercions, such as "Object --> String --> Long --> Integer".
- *
- * @param <S>
- * source type (input)
- * @param <T>
- * target type (output)
- * @param sourceType
- * the source coercion type (use void.class for coercions from null)
- * @param targetType
- * defines the target type
- * @return a string identifying the series of coercions, or the empty string if no coercion is necessary
- */
- <S, T> String explain(Class<S> sourceType, Class<T> targetType);
-
- /**
- * Clears cached information stored by the TypeCoercer.
- */
- void clearCache();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
deleted file mode 100644
index c4c5c6d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.ioc.util;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-/**
- * Used (as part of a {@link UnknownValueException} to identify what available values
- * are present.
- *
- * @since 5.2.0
- */
-public class AvailableValues
-{
- private final String valueType;
-
- private final List<String> values;
-
- /**
- * @param valueType
- * a word or phrase that describes what the values are such as "component types" or "service ids"
- *@param values
- * a set of objects defining the values; the values will be converted to strings and sorted into
- * ascending order
- */
- public AvailableValues(String valueType, Collection<?> values)
- {
- this.valueType = valueType;
- this.values = sortValues(values);
- }
-
- public AvailableValues(String valueType, Map<?, ?> map)
- {
- this(valueType, map.keySet());
- }
-
- private static List<String> sortValues(Collection<?> values)
- {
- List<String> result = CollectionFactory.newList();
-
- for (Object v : values)
- {
- result.add(String.valueOf(v));
- }
-
- Collections.sort(result);
-
- return Collections.unmodifiableList(result);
- }
-
- /** The type of value, i.e., "component types" or "service ids". */
- public String getValueType()
- {
- return valueType;
- }
-
- /** The values, as strings, in sorted order. */
- public List<String> getValues()
- {
- return values;
- }
-
- @Override
- public String toString()
- {
- return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
deleted file mode 100644
index f5aff7e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
+++ /dev/null
@@ -1,499 +0,0 @@
-// 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.ioc.util;
-
-import java.io.Serializable;
-import java.util.*;
-
-/**
- * An mapped collection where the keys are always strings and access to values is case-insensitive. The case of keys in
- * the map is <em>maintained</em>, but on any access to a key (directly or indirectly), all key comparisons are
- * performed in a case-insensitive manner. The map implementation is intended to support a reasonably finite number
- * (dozens or hundreds, not thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of
- * entries rather than hash bucket. It is also geared towards a largely static map, one that is created and then used
- * without modification.
- *
- * @param <V> the type of value stored
- */
-public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
-{
- private static final long serialVersionUID = 3362718337611953298L;
-
- private static final int NULL_HASH = Integer.MIN_VALUE;
-
- private static final int DEFAULT_SIZE = 20;
-
- private static class CIMEntry<V> implements Map.Entry<String, V>, Serializable
- {
- private static final long serialVersionUID = 6713986085221148350L;
-
- private String key;
-
- private final int hashCode;
-
- V value;
-
- public CIMEntry(final String key, final int hashCode, V value)
- {
- this.key = key;
- this.hashCode = hashCode;
- this.value = value;
- }
-
- @Override
- public String getKey()
- {
- return key;
- }
-
- @Override
- public V getValue()
- {
- return value;
- }
-
- @Override
- public V setValue(V value)
- {
- V result = this.value;
-
- this.value = value;
-
- return result;
- }
-
- /**
- * Returns true if both keys are null, or if the provided key is the same as, or case-insensitively equal to,
- * the entrie's key.
- *
- * @param key to compare against
- * @return true if equal
- */
- @SuppressWarnings({ "StringEquality" })
- boolean matches(String key)
- {
- return key == this.key || (key != null && key.equalsIgnoreCase(this.key));
- }
-
- boolean valueMatches(Object value)
- {
- return value == this.value || (value != null && value.equals(this.value));
- }
- }
-
- private class EntrySetIterator implements Iterator
- {
- int expectedModCount = modCount;
-
- int index;
-
- int current = -1;
-
- @Override
- public boolean hasNext()
- {
- return index < size;
- }
-
- @Override
- public Object next()
- {
- check();
-
- if (index >= size) throw new NoSuchElementException();
-
- current = index++;
-
- return entries[current];
- }
-
- @Override
- public void remove()
- {
- check();
-
- if (current < 0) throw new NoSuchElementException();
-
- new Position(current, true).remove();
-
- expectedModCount = modCount;
- }
-
- private void check()
- {
- if (expectedModCount != modCount) throw new ConcurrentModificationException();
- }
- }
-
- @SuppressWarnings("unchecked")
- private class EntrySet extends AbstractSet
- {
- @Override
- public Iterator iterator()
- {
- return new EntrySetIterator();
- }
-
- @Override
- public int size()
- {
- return size;
- }
-
- @Override
- public void clear()
- {
- CaseInsensitiveMap.this.clear();
- }
-
- @Override
- public boolean contains(Object o)
- {
- if (!(o instanceof Map.Entry)) return false;
-
- Map.Entry e = (Map.Entry) o;
-
- Position position = select(e.getKey());
-
- return position.isFound() && position.entry().valueMatches(e.getValue());
- }
-
- @Override
- public boolean remove(Object o)
- {
- if (!(o instanceof Map.Entry)) return false;
-
- Map.Entry e = (Map.Entry) o;
-
- Position position = select(e.getKey());
-
- if (position.isFound() && position.entry().valueMatches(e.getValue()))
- {
- position.remove();
- return true;
- }
-
- return false;
- }
-
- }
-
- private class Position
- {
- private final int cursor;
-
- private final boolean found;
-
- Position(int cursor, boolean found)
- {
- this.cursor = cursor;
- this.found = found;
- }
-
- boolean isFound()
- {
- return found;
- }
-
- CIMEntry<V> entry()
- {
- return entries[cursor];
- }
-
- V get()
- {
- return found ? entries[cursor].value : null;
- }
-
- V remove()
- {
- if (!found) return null;
-
- V result = entries[cursor].value;
-
- // Remove the entry by shifting everything else down.
-
- System.arraycopy(entries, cursor + 1, entries, cursor, size - cursor - 1);
-
- // We shifted down, leaving one (now duplicate) entry behind.
-
- entries[--size] = null;
-
- // A structural change for sure
-
- modCount++;
-
- return result;
- }
-
- @SuppressWarnings("unchecked")
- V put(String key, int hashCode, V newValue)
- {
- if (found)
- {
- CIMEntry<V> e = entries[cursor];
-
- V result = e.value;
-
- // Not a structural change, so no change to modCount
-
- // Update the key (to maintain case). By definition, the hash code
- // will not change.
-
- e.key = key;
- e.value = newValue;
-
- return result;
- }
-
- // Not found, we're going to add it.
-
- int newSize = size + 1;
-
- if (newSize == entries.length)
- {
- // Time to expand!
-
- int newCapacity = (size * 3) / 2 + 1;
-
- CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
-
- System.arraycopy(entries, 0, newEntries, 0, cursor);
-
- System.arraycopy(entries, cursor, newEntries, cursor + 1, size - cursor);
-
- entries = newEntries;
- }
- else
- {
- // Open up a space for the new entry
-
- System.arraycopy(entries, cursor, entries, cursor + 1, size - cursor);
- }
-
- CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, newValue);
- entries[cursor] = newEntry;
-
- size++;
-
- // This is definately a structural change
-
- modCount++;
-
- return null;
- }
-
- }
-
- // The list of entries. This is kept sorted by hash code. In some cases, there may be different
- // keys with the same hash code in adjacent indexes.
- private CIMEntry<V>[] entries;
-
- private int size = 0;
-
- // Used by iterators to check for concurrent modifications
-
- private transient int modCount = 0;
-
- private transient Set<Map.Entry<String, V>> entrySet;
-
- public CaseInsensitiveMap()
- {
- this(DEFAULT_SIZE);
- }
-
- @SuppressWarnings("unchecked")
- public CaseInsensitiveMap(int size)
- {
- entries = new CIMEntry[Math.max(size, 3)];
- }
-
- public CaseInsensitiveMap(Map<String, ? extends V> map)
- {
- this(map.size());
-
- for (Map.Entry<String, ? extends V> entry : map.entrySet())
- {
- put(entry.getKey(), entry.getValue());
- }
- }
-
- @Override
- public void clear()
- {
- for (int i = 0; i < size; i++)
- entries[i] = null;
-
- size = 0;
- modCount++;
- }
-
- @Override
- public boolean isEmpty()
- {
- return size == 0;
- }
-
- @Override
- public int size()
- {
- return size;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public V put(String key, V value)
- {
- int hashCode = caseInsenitiveHashCode(key);
-
- return select(key, hashCode).put(key, hashCode, value);
- }
-
- @Override
- public boolean containsKey(Object key)
- {
- return select(key).isFound();
- }
-
- @Override
- public V get(Object key)
- {
- return select(key).get();
- }
-
- @Override
- public V remove(Object key)
- {
- return select(key).remove();
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Set<Map.Entry<String, V>> entrySet()
- {
- if (entrySet == null) entrySet = new EntrySet();
-
- return entrySet;
- }
-
- private Position select(Object key)
- {
- if (key == null || key instanceof String)
- {
- String keyString = (String) key;
- return select(keyString, caseInsenitiveHashCode(keyString));
- }
-
- return new Position(0, false);
- }
-
- /**
- * Searches the elements for the index of the indicated key and (case insensitive) hash code. Sets the _cursor and
- * _found attributes.
- */
- private Position select(String key, int hashCode)
- {
- if (size == 0) return new Position(0, false);
-
- int low = 0;
- int high = size - 1;
-
- int cursor;
-
- while (low <= high)
- {
- cursor = (low + high) >> 1;
-
- CIMEntry e = entries[cursor];
-
- if (e.hashCode < hashCode)
- {
- low = cursor + 1;
- continue;
- }
-
- if (e.hashCode > hashCode)
- {
- high = cursor - 1;
- continue;
- }
-
- return tunePosition(key, hashCode, cursor);
- }
-
- return new Position(low, false);
- }
-
- /**
- * select() has located a matching hashCode, but there's an outlying possibility that multiple keys share the same
- * hashCode. Backup the cursor until we get to locate the initial hashCode match, then march forward until the key
- * is located, or the hashCode stops matching.
- *
- * @param key
- * @param hashCode
- */
- private Position tunePosition(String key, int hashCode, int cursor)
- {
- boolean found = false;
-
- while (cursor > 0)
- {
- if (entries[cursor - 1].hashCode != hashCode) break;
-
- cursor--;
- }
-
- while (true)
- {
- if (entries[cursor].matches(key))
- {
- found = true;
- break;
- }
-
- // Advance to the next entry.
-
- cursor++;
-
- // If out of entries,
- if (cursor >= size || entries[cursor].hashCode != hashCode) break;
- }
-
- return new Position(cursor, found);
- }
-
- static int caseInsenitiveHashCode(String input)
- {
- if (input == null) return NULL_HASH;
-
- int length = input.length();
- int hash = 0;
-
- // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
- // changes its implementation. Let's hope this is reasonably fast.
-
- for (int i = 0; i < length; i++)
- {
- int ch = input.charAt(i);
-
- int caselessCh = Character.toLowerCase(ch);
-
- hash = 31 * hash + caselessCh;
- }
-
- return hash;
- }
-
-}
[14/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
Fourth pass creating the BeanModel and Commons packages.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/eb7ec86e
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/eb7ec86e
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/eb7ec86e
Branch: refs/heads/beanmodel-split
Commit: eb7ec86e3368e4a4e20d88c8f009d88fd1d37740
Parents: dd95846
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 19:45:14 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 19:45:14 2014 -0200
----------------------------------------------------------------------
beanmodel/build.gradle | 1 +
.../beaneditor/BeanModelSourceBuilder.java | 121 +++++
.../internal/InternalBeanModelUtils.java | 145 ------
.../internal/beaneditor/BeanModelImpl.java | 4 +-
.../internal/beaneditor/BeanModelUtils.java | 4 +-
.../internal/beaneditor/PropertyModelImpl.java | 10 +-
.../services/PropertyConduitSourceImpl.java | 10 +-
.../services/ClassPropertyAdapterImpl.java | 249 +++++++++
.../services/PlasticClassListenerLogger.java | 47 ++
.../services/PlasticProxyFactoryImpl.java | 285 +++++++++++
.../internal/services/PropertyAccessImpl.java | 217 ++++++++
.../internal/services/PropertyAdapterImpl.java | 273 ++++++++++
commons/build.gradle | 1 +
.../internal/services/StringInternerImpl.java | 54 ++
.../org/apache/tapestry5/ioc/Configuration.java | 53 ++
.../tapestry5/ioc/MappedConfiguration.java | 81 +++
.../tapestry5/ioc/OrderedConfiguration.java | 84 +++
.../ioc/internal/BasicTypeCoercions.java | 342 +++++++++++++
.../AccessableObjectAnnotationProvider.java | 46 ++
.../services/AnnotationProviderChain.java | 59 +++
.../ioc/internal/services/CompoundCoercion.java | 54 ++
.../ioc/internal/services/ServiceMessages.java | 68 +++
.../ioc/internal/services/StringLocation.java | 65 +++
.../ioc/internal/services/TypeCoercerImpl.java | 508 +++++++++++++++++++
.../ioc/internal/util/InheritanceSearch.java | 159 ++++++
.../ioc/internal/util/InternalCommonsUtils.java | 388 ++++++++++++++
.../ioc/internal/util/InternalStringUtils.java | 203 --------
.../ioc/internal/util/LockSupport.java | 89 ++++
.../ioc/internal/util/MessageFormatterImpl.java | 65 +++
.../ioc/internal/util/MessagesImpl.java | 74 +++
.../ioc/internal/util/TapestryException.java | 23 +-
.../tapestry5/ioc/util/AbstractMessages.java | 94 ++++
.../tapestry5/ioc/util/AvailableValues.java | 4 +-
.../apache/tapestry5/ioc/util/TimeInterval.java | 195 +++++++
.../tapestry5/util/StringToEnumCoercion.java | 91 ++++
.../internal/TapestryInternalUtils.java | 8 +-
.../internal/services/StringInternerImpl.java | 53 --
.../org/apache/tapestry5/ioc/Configuration.java | 53 --
.../tapestry5/ioc/MappedConfiguration.java | 81 ---
.../tapestry5/ioc/OrderedConfiguration.java | 84 ---
.../AccessableObjectAnnotationProvider.java | 46 --
.../services/AnnotationProviderChain.java | 59 ---
.../services/ClassPropertyAdapterImpl.java | 250 ---------
.../ioc/internal/services/CompoundCoercion.java | 54 --
.../services/PlasticClassListenerLogger.java | 47 --
.../services/PlasticProxyFactoryImpl.java | 286 -----------
.../internal/services/PropertyAccessImpl.java | 217 --------
.../internal/services/PropertyAdapterImpl.java | 273 ----------
.../ioc/internal/services/ServiceMessages.java | 68 ---
.../ioc/internal/services/StringLocation.java | 65 ---
.../ioc/internal/services/TypeCoercerImpl.java | 508 -------------------
.../ioc/internal/util/InheritanceSearch.java | 159 ------
.../ioc/internal/util/InternalUtils.java | 138 +++--
.../ioc/internal/util/LockSupport.java | 89 ----
.../ioc/internal/util/MessageFormatterImpl.java | 65 ---
.../ioc/internal/util/MessagesImpl.java | 74 ---
.../ioc/modules/TapestryIOCModule.java | 297 +----------
.../tapestry5/ioc/util/AbstractMessages.java | 94 ----
.../apache/tapestry5/ioc/util/TimeInterval.java | 195 -------
.../tapestry5/util/StringToEnumCoercion.java | 91 ----
60 files changed, 3855 insertions(+), 3665 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
index c09ebdd..fba43b7 100644
--- a/beanmodel/build.gradle
+++ b/beanmodel/build.gradle
@@ -26,6 +26,7 @@ dependencies {
compile project(":plastic")
compile project(":tapestry5-annotations")
compile project(":commons")
+ compile "org.slf4j:slf4j-api:${versions.slf4j}"
// Antlr3 tool path used with the antlr3 task
antlr3 "org.antlr:antlr:3.5.2"
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
new file mode 100644
index 0000000..8cef66e
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
@@ -0,0 +1,121 @@
+// Copyright 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.beaneditor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.naming.OperationNotSupportedException;
+
+import org.apache.tapestry5.internal.services.BeanModelSourceImpl;
+import org.apache.tapestry5.internal.services.PropertyConduitSourceImpl;
+import org.apache.tapestry5.internal.services.StringInterner;
+import org.apache.tapestry5.internal.services.StringInternerImpl;
+import org.apache.tapestry5.ioc.Configuration;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
+import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
+import org.apache.tapestry5.ioc.internal.services.PropertyAccessImpl;
+import org.apache.tapestry5.ioc.internal.services.TypeCoercerImpl;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.services.BeanModelSource;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+import org.apache.tapestry5.services.PropertyConduitSource;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for creating {@link BeanModelSource} instances without
+ * Tapestry-IoC. Usage of Tapestry-IoC is still recommended.
+ */
+public class BeanModelSourceBuilder {
+
+ private TypeCoercer typeCoercer;
+ private PropertyAccess propertyAccess;
+ private PropertyConduitSource propertyConduitSource;
+ private PlasticProxyFactory plasticProxyFactory;
+ private DataTypeAnalyzer dataTypeAnalyzer;
+ private ObjectLocator objectLocator;
+ private StringInterner stringInterner;
+
+ /**
+ * Sets the {@link TypeCoercer} to be used.
+ */
+ public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer) {
+ this.typeCoercer = typeCoercer;
+// propertyAccess = new PropertyAcc
+ return this;
+ }
+
+ public BeanModelSource build()
+ {
+
+ if (typeCoercer == null)
+ {
+ createTypeCoercer();
+ }
+
+ if (propertyAccess == null)
+ {
+ propertyAccess = new PropertyAccessImpl();
+ }
+
+ if (stringInterner == null)
+ {
+ stringInterner = new StringInternerImpl();
+ }
+
+ if (plasticProxyFactory == null)
+ {
+ plasticProxyFactory = new PlasticProxyFactoryImpl(getClass().getClassLoader(), LoggerFactory.getLogger(PlasticProxyFactory.class));
+ }
+
+ if (propertyConduitSource == null)
+ {
+ propertyConduitSource = new PropertyConduitSourceImpl(propertyAccess, plasticProxyFactory, typeCoercer, stringInterner);
+ }
+
+ return new BeanModelSourceImpl(typeCoercer, propertyAccess, propertyConduitSource, plasticProxyFactory, dataTypeAnalyzer, objectLocator);
+
+ }
+
+ private void createTypeCoercer() {
+ CoercionTupleConfiguration configuration = new CoercionTupleConfiguration();
+ BasicTypeCoercions.provideBasicTypeCoercions(configuration);
+ typeCoercer = new TypeCoercerImpl(configuration.getTuples());
+ }
+
+ final private static class CoercionTupleConfiguration implements Configuration<CoercionTuple> {
+
+ final private Collection<CoercionTuple> tuples = new ArrayList<CoercionTuple>();
+
+ @Override
+ public void add(CoercionTuple tuble) {
+ tuples.add(tuble);
+ }
+
+ @Override
+ public void addInstance(Class<? extends CoercionTuple> clazz) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Collection<CoercionTuple> getTuples() {
+ return tuples;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
deleted file mode 100644
index 88f4c7f..0000000
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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.internal;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.regex.Pattern;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
-
-/**
- * Some methods broken off tapestry-core's InternalUtils to avoid bringing the whole class
- * plus its multiple dependencies to the BeanModel package.
- */
-public class InternalBeanModelUtils {
-
- public static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
-
- /**
- * @since 5.3
- */
- private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-
-
- /**
- * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
- * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
- * underscore).
- *
- * @param expression a property expression
- * @return the expression with punctuation removed
- */
- public static String extractIdFromPropertyExpression(String expression)
- {
- return replace(expression, NON_WORD_PATTERN, "");
- }
-
- public static String replace(String input, Pattern pattern, String replacement)
- {
- return pattern.matcher(input).replaceAll(replacement);
- }
-
- /**
- * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
- * user presentable form.
- */
- public static String defaultLabel(String id, Messages messages, String propertyExpression)
- {
- String key = id + "-label";
-
- if (messages.contains(key))
- return messages.get(key);
-
- return toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
- }
-
- /**
- * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
- * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
- * following word), thus "user_id" also becomes "User Id".
- */
- public static String toUserPresentable(String id)
- {
- StringBuilder builder = new StringBuilder(id.length() * 2);
-
- char[] chars = id.toCharArray();
- boolean postSpace = true;
- boolean upcaseNext = true;
-
- for (char ch : chars)
- {
- if (upcaseNext)
- {
- builder.append(Character.toUpperCase(ch));
- upcaseNext = false;
-
- continue;
- }
-
- if (ch == '_')
- {
- builder.append(' ');
- upcaseNext = true;
- continue;
- }
-
- boolean upperCase = Character.isUpperCase(ch);
-
- if (upperCase && !postSpace)
- builder.append(' ');
-
- builder.append(ch);
-
- postSpace = upperCase;
- }
-
- return builder.toString();
- }
-
- /**
- * @since 5.3
- */
- public static AnnotationProvider toAnnotationProvider(final Class element)
- {
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationClass.cast(element.getAnnotation(annotationClass));
- }
- };
- }
-
- public static AnnotationProvider toAnnotationProvider(final Method element)
- {
- if (element == null)
- return NULL_ANNOTATION_PROVIDER;
-
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return element.getAnnotation(annotationClass);
- }
- };
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/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
index b72a3d6..3b71f0e 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
@@ -22,7 +22,7 @@ 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.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.UnknownValueException;
@@ -93,7 +93,7 @@ public class BeanModelImpl<T> implements BeanModel<T>
private void validateNewPropertyName(String propertyName)
{
- assert InternalStringUtils.isNonBlank(propertyName);
+ assert InternalCommonsUtils.isNonBlank(propertyName);
if (properties.containsKey(propertyName))
throw new RuntimeException(String.format(
"Bean editor model for %s already contains a property model for property '%s'.",
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
index 154ee79..207fb97 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
@@ -15,7 +15,7 @@
package org.apache.tapestry5.internal.beaneditor;
import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
/**
* Utilities used in a few places to modify an existing {@link BeanModel}.
@@ -54,7 +54,7 @@ public final class BeanModelUtils
private static final String join(String firstList, String optionalSecondList)
{
- if (InternalStringUtils.isBlank(optionalSecondList))
+ if (InternalCommonsUtils.isBlank(optionalSecondList))
return firstList;
return firstList + "," + optionalSecondList;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/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
index 4632818..24d0b2d 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -20,9 +20,9 @@ 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.InternalBeanModelUtils;
import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
@SuppressWarnings("all")
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
this.name = name;
this.conduit = conduit;
- id = InternalBeanModelUtils.extractIdFromPropertyExpression(name);
+ id = InternalCommonsUtils.extractIdFromPropertyExpression(name);
- label = InternalBeanModelUtils.defaultLabel(id, messages, name);
+ label = InternalCommonsUtils.defaultLabel(id, messages, name);
// TAP5-2305
if (conduit != null)
@@ -87,7 +87,7 @@ public class PropertyModelImpl implements PropertyModel
public PropertyModel label(String label)
{
- assert InternalStringUtils.isNonBlank(label);
+ assert InternalCommonsUtils.isNonBlank(label);
this.label = label;
return this;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 4ce072e..09d234c 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -19,7 +19,6 @@ import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.Tree;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.internal.InternalPropertyConduit;
import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -30,7 +29,8 @@ import org.apache.tapestry5.ioc.annotations.PostInjection;
import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
import org.apache.tapestry5.ioc.services.*;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.ExceptionUtils;
@@ -1107,7 +1107,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
- InternalStringUtils.joinSorted(tokenNames));
+ InternalCommonsUtils.joinSorted(tokenNames));
return new RuntimeException(message);
}
@@ -1260,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
Type returnType = GenericsUtils.extractActualType(activeType, method);
- return new Term(returnType, toUniqueId(method), InternalBeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+ return new Term(returnType, toUniqueId(method), InternalCommonsUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
{
@@ -1364,7 +1364,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
public PropertyConduit create(Class rootClass, String expression)
{
assert rootClass != null;
- assert InternalStringUtils.isNonBlank(expression);
+ assert InternalCommonsUtils.isNonBlank(expression);
MultiKey key = new MultiKey(rootClass, expression);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
new file mode 100644
index 0000000..5d6dfec
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
@@ -0,0 +1,249 @@
+// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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.ioc.internal.services;
+
+import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+
+public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
+{
+ private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap();
+
+ private final Class beanType;
+
+ public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> descriptors)
+ {
+ this.beanType = beanType;
+
+ // lazy init
+ Map<String, List<Method>> nonBridgeMethods = null;
+
+ for (PropertyDescriptor pd : descriptors)
+ {
+ // Indexed properties will have a null propertyType (and a non-null
+ // indexedPropertyType). We ignore indexed properties.
+
+ final Class<?> thisPropertyType = pd.getPropertyType();
+ if (thisPropertyType == null)
+ continue;
+
+ Method readMethod = pd.getReadMethod();
+ Method writeMethod = pd.getWriteMethod();
+
+ // TAP5-1493
+ if (readMethod != null && readMethod.isBridge())
+ {
+ if (nonBridgeMethods == null)
+ {
+ nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+ }
+ readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods);
+ }
+
+ // TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed
+ if (readMethod == null) {
+ final String prefix = thisPropertyType != boolean.class ? "get" : "is";
+ try
+ {
+ Method method = beanType.getMethod(prefix + capitalize(pd.getName()));
+ final Class<?> returnType = method.getReturnType();
+ if (returnType.equals(thisPropertyType) || returnType.isInstance(thisPropertyType)) {
+ readMethod = method;
+ }
+ }
+ catch (SecurityException e) {
+ // getter not usable.
+ }
+ catch (NoSuchMethodException e)
+ {
+ // getter doesn't exist.
+ }
+ }
+
+ if (writeMethod != null && writeMethod.isBridge())
+ {
+ if (nonBridgeMethods == null)
+ {
+ nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+ }
+ writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
+ }
+
+ // TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed
+ if (writeMethod == null) {
+ try
+ {
+ Method method = beanType.getMethod("set" + capitalize(pd.getName()), pd.getPropertyType());
+ final Class<?> returnType = method.getReturnType();
+ if (returnType.equals(void.class)) {
+ writeMethod = method;
+ }
+ }
+ catch (SecurityException e) {
+ // setter not usable.
+ }
+ catch (NoSuchMethodException e)
+ {
+ // setter doesn't exist.
+ }
+ }
+
+ Class propertyType = readMethod == null ? thisPropertyType : GenericsUtils.extractGenericReturnType(
+ beanType, readMethod);
+
+ PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, writeMethod);
+
+ adapters.put(pa.getName(), pa);
+ }
+
+ // Now, add any public fields (even if static) that do not conflict
+
+ for (Field f : beanType.getFields())
+ {
+ String name = f.getName();
+
+ if (!adapters.containsKey(name))
+ {
+ Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f);
+ PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f);
+
+ adapters.put(name, pa);
+ }
+ }
+ }
+
+ private static String capitalize(String name)
+ {
+ return Character.toUpperCase(name.charAt(0)) + name.substring(1);
+ }
+
+ /**
+ * Find a replacement for the method (if one exists)
+ * @param method A method
+ * @param groupedMethods Methods mapped by name
+ * @return A method from groupedMethods with the same name / param count
+ * (default to providedmethod if none found)
+ */
+ private Method findMethodWithSameNameAndParamCount(Method method, Map<String, List<Method>> groupedMethods) {
+ List<Method> methodGroup = groupedMethods.get(method.getName());
+ if (methodGroup != null)
+ {
+ for (Method nonBridgeMethod : methodGroup)
+ {
+ if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length)
+ {
+ // return the non-bridge method with the same name / argument count
+ return nonBridgeMethod;
+ }
+ }
+ }
+
+ // default to the provided method
+ return method;
+ }
+
+ /**
+ * Find all of the public methods that are not bridge methods and
+ * group them by method name
+ *
+ * {@see Method#isBridge()}
+ * @param type Bean type
+ * @return
+ */
+ private Map<String, List<Method>> groupNonBridgeMethodsByName(Class type)
+ {
+ Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap();
+ for (Method method : type.getMethods())
+ {
+ if (!method.isBridge())
+ {
+ List<Method> methodGroup = methodGroupsByName.get(method.getName());
+ if (methodGroup == null)
+ {
+ methodGroup = CollectionFactory.newList();
+ methodGroupsByName.put(method.getName(), methodGroup);
+ }
+ methodGroup.add(method);
+ }
+ }
+ return methodGroupsByName;
+ }
+
+ @Override
+ public Class getBeanType()
+ {
+ return beanType;
+ }
+
+ @Override
+ public String toString()
+ {
+ String names = InternalCommonsUtils.joinSorted(adapters.keySet());
+
+ return String.format("<ClassPropertyAdaptor %s: %s>", beanType.getName(), names);
+ }
+
+ @Override
+ public List<String> getPropertyNames()
+ {
+ return InternalCommonsUtils.sortedKeys(adapters);
+ }
+
+ @Override
+ public PropertyAdapter getPropertyAdapter(String name)
+ {
+ return adapters.get(name);
+ }
+
+ @Override
+ public Object get(Object instance, String propertyName)
+ {
+ return adaptorFor(propertyName).get(instance);
+ }
+
+ @Override
+ public void set(Object instance, String propertyName, Object value)
+ {
+ adaptorFor(propertyName).set(instance, value);
+ }
+
+ @Override
+ public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) {
+ return adaptorFor(propertyName).getAnnotation(annotationClass);
+ }
+
+ private PropertyAdapter adaptorFor(String name)
+ {
+ PropertyAdapter pa = adapters.get(name);
+
+ if (pa == null)
+ throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
+
+ return pa;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
new file mode 100644
index 0000000..8ebdede
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
@@ -0,0 +1,47 @@
+// Copyright 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.ioc.internal.services;
+
+import org.apache.tapestry5.plastic.ClassType;
+import org.apache.tapestry5.plastic.PlasticClassEvent;
+import org.apache.tapestry5.plastic.PlasticClassListener;
+import org.slf4j.Logger;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+public class PlasticClassListenerLogger implements PlasticClassListener
+{
+ private final Logger logger;
+
+ public PlasticClassListenerLogger(Logger logger)
+ {
+ this.logger = logger;
+ }
+
+ @Override
+ public void classWillLoad(PlasticClassEvent event)
+ {
+ if (logger.isDebugEnabled())
+ {
+ Marker marker = MarkerFactory.getMarker(event.getPrimaryClassName());
+
+ String extendedClassName = event.getType() == ClassType.PRIMARY ? event.getPrimaryClassName() : String
+ .format("%s (%s for %s)", event.getClassName(), event.getType(), event.getPrimaryClassName());
+
+ logger.debug(marker,
+ String.format("Loading class %s:\n%s", extendedClassName, event.getDissasembledBytecode()));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
new file mode 100644
index 0000000..a23ecec
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
@@ -0,0 +1,285 @@
+// Copyright 2011, 2012 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.ioc.internal.services;
+
+import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
+import org.apache.tapestry5.internal.plastic.asm.Type;
+import org.apache.tapestry5.internal.plastic.asm.tree.*;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
+import org.apache.tapestry5.plastic.*;
+import org.slf4j.Logger;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+public class PlasticProxyFactoryImpl implements PlasticProxyFactory
+{
+ public static final String INTERNAL_GET_DELEGATE = "_____internalGetDelegate_DONT_CALL_THIS_METHOD_____";
+
+ private final PlasticManager manager;
+
+ private final Map<String, Location> memberToLocation = CollectionFactory.newConcurrentMap();
+
+ public PlasticProxyFactoryImpl(ClassLoader parentClassLoader, Logger logger)
+ {
+ this(PlasticManager.withClassLoader(parentClassLoader).create(), logger);
+ }
+
+ public PlasticProxyFactoryImpl(PlasticManager manager, Logger logger)
+ {
+ assert manager != null;
+
+ this.manager = manager;
+
+ if (logger != null)
+ {
+ manager.addPlasticClassListener(new PlasticClassListenerLogger(logger));
+ }
+ }
+
+ @Override
+ public ClassLoader getClassLoader()
+ {
+ return manager.getClassLoader();
+ }
+
+ @Override
+ public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback)
+ {
+ return manager.createProxy(interfaceType, implementationType, callback);
+ }
+
+ @Override
+ public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
+ {
+ return manager.createProxy(interfaceType, callback);
+ }
+
+
+ @Override
+ public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType,
+ Class<? extends T> implementationType)
+ {
+ return manager.createProxyTransformation(interfaceType, implementationType);
+ }
+
+ @Override
+ public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType)
+ {
+ return createProxyTransformation(interfaceType, null);
+ }
+
+ @Override
+ public <T> T createProxy(final Class<T> interfaceType, final ObjectCreator<T> creator, final String description)
+ { return createProxy(interfaceType, null, creator, description);
+ }
+
+ @Override
+ public <T> T createProxy(final Class<T> interfaceType, final Class<? extends T> implementationType,
+ final ObjectCreator<T> creator, final String description)
+ {
+ assert creator != null;
+ assert InternalCommonsUtils.isNonBlank(description);
+
+ ClassInstantiator<T> instantiator = createProxy(interfaceType, implementationType, new PlasticClassTransformer()
+ {
+ @Override
+ public void transform(PlasticClass plasticClass)
+ {
+ final PlasticField objectCreatorField = plasticClass.introduceField(ObjectCreator.class, "creator")
+ .inject(creator);
+
+ final String interfaceTypeName = interfaceType.getName();
+ PlasticMethod delegateMethod = plasticClass.introducePrivateMethod(interfaceTypeName, "delegate",
+ null, null);
+
+ final InstructionBuilderCallback returnCreateObject = new InstructionBuilderCallback()
+ {
+ @Override
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadThis().getField(objectCreatorField);
+ builder.invoke(ObjectCreator.class, Object.class, "createObject");
+ builder.checkcast(interfaceType).returnResult();
+ }
+ };
+
+ delegateMethod.changeImplementation(returnCreateObject);
+
+ for (Method method : interfaceType.getMethods())
+ {
+ plasticClass.introduceMethod(method).delegateTo(delegateMethod);
+ }
+
+ // TA5-2235
+ MethodDescription getDelegateMethodDescription =
+ new MethodDescription(interfaceType.getName(), INTERNAL_GET_DELEGATE);
+ plasticClass.introduceMethod(getDelegateMethodDescription, returnCreateObject);
+
+ plasticClass.addToString(description);
+
+ }
+ });
+
+ return interfaceType.cast(instantiator.newInstance());
+ }
+
+ private ClassNode readClassNode(Class clazz)
+ {
+ byte[] bytecode = PlasticInternalUtils.readBytecodeForClass(manager.getClassLoader(), clazz.getName(), false);
+
+ return bytecode == null ? null : PlasticInternalUtils.convertBytecodeToClassNode(bytecode);
+ }
+
+ @Override
+ public Location getMethodLocation(final Method method)
+ {
+ ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
+ {
+ @Override
+ public String createObject()
+ {
+ return InternalCommonsUtils.asString(method);
+ }
+ };
+
+ return getMemberLocation(method, method.getName(), Type.getMethodDescriptor(method),
+ descriptionCreator);
+ }
+
+ @Override
+ public Location getConstructorLocation(final Constructor constructor)
+ {
+ ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
+ {
+ @Override
+ public String createObject()
+ {
+ StringBuilder builder = new StringBuilder(constructor.getDeclaringClass().getName()).append("(");
+ String sep = "";
+
+ for (Class parameterType : constructor.getParameterTypes())
+ {
+ builder.append(sep);
+ builder.append(parameterType.getSimpleName());
+
+ sep = ", ";
+ }
+
+ builder.append(")");
+
+ return builder.toString();
+ }
+ };
+
+ return getMemberLocation(constructor, "<init>", Type.getConstructorDescriptor(constructor),
+ descriptionCreator);
+ }
+
+ @Override
+ public void clearCache()
+ {
+ memberToLocation.clear();
+ }
+
+
+ public Location getMemberLocation(Member member, String methodName, String memberTypeDesc, ObjectCreator<String> textDescriptionCreator)
+ {
+ String className = member.getDeclaringClass().getName();
+
+ String key = className + ":" + methodName + ":" + memberTypeDesc;
+
+ Location location = memberToLocation.get(key);
+
+ if (location == null)
+ {
+ location = constructMemberLocation(member, methodName, memberTypeDesc, textDescriptionCreator.createObject());
+
+ memberToLocation.put(key, location);
+ }
+
+ return location;
+
+ }
+
+ private Location constructMemberLocation(Member member, String methodName, String memberTypeDesc, String textDescription)
+ {
+
+ ClassNode classNode = readClassNode(member.getDeclaringClass());
+
+ if (classNode == null)
+ {
+ throw new RuntimeException(String.format("Unable to read class file for %s (to gather line number information).",
+ textDescription));
+ }
+
+ for (MethodNode mn : (List<MethodNode>) classNode.methods)
+ {
+ if (mn.name.equals(methodName) && mn.desc.equals(memberTypeDesc))
+ {
+ int lineNumber = findFirstLineNumber(mn.instructions);
+
+ // If debugging info is not available, we may lose the line number data, in which case,
+ // just generate the Location from the textDescription.
+
+ if (lineNumber < 1)
+ {
+ break;
+ }
+
+ String description = String.format("%s (at %s:%d)", textDescription, classNode.sourceFile, lineNumber);
+
+ return new StringLocation(description, lineNumber);
+ }
+ }
+
+ // Didn't find it. Odd.
+
+ return new StringLocation(textDescription, 0);
+ }
+
+ private int findFirstLineNumber(InsnList instructions)
+ {
+ for (AbstractInsnNode node = instructions.getFirst(); node != null; node = node.getNext())
+ {
+ if (node instanceof LineNumberNode)
+ {
+ return ((LineNumberNode) node).line;
+ }
+ }
+
+ return -1;
+ }
+
+ @Override
+ public void addPlasticClassListener(PlasticClassListener listener)
+ {
+ manager.addPlasticClassListener(listener);
+ }
+
+ @Override
+ public void removePlasticClassListener(PlasticClassListener listener)
+ {
+ manager.removePlasticClassListener(listener);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
new file mode 100644
index 0000000..8dd1e02
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
@@ -0,0 +1,217 @@
+// Copyright 2006, 2007, 2008, 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.ioc.internal.services;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+
+@SuppressWarnings("unchecked")
+public class PropertyAccessImpl implements PropertyAccess
+{
+ private final Map<Class, ClassPropertyAdapter> adapters = CollectionFactory.newConcurrentMap();
+
+ @Override
+ public Object get(Object instance, String propertyName)
+ {
+ return getAdapter(instance).get(instance, propertyName);
+ }
+
+ @Override
+ public void set(Object instance, String propertyName, Object value)
+ {
+ getAdapter(instance).set(instance, propertyName, value);
+ }
+
+ @Override
+ public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) {
+ return getAdapter(instance).getAnnotation(instance, propertyName, annotationClass);
+ }
+
+
+ /**
+ * Clears the cache of adapters and asks the {@link Introspector} to clear its cache.
+ */
+ @Override
+ public synchronized void clearCache()
+ {
+ adapters.clear();
+
+ Introspector.flushCaches();
+ }
+
+ @Override
+ public ClassPropertyAdapter getAdapter(Object instance)
+ {
+ return getAdapter(instance.getClass());
+ }
+
+ @Override
+ public ClassPropertyAdapter getAdapter(Class forClass)
+ {
+ ClassPropertyAdapter result = adapters.get(forClass);
+
+ if (result == null)
+ {
+ result = buildAdapter(forClass);
+ adapters.put(forClass, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Builds a new adapter and updates the _adapters cache. This not only guards access to the adapter cache, but also
+ * serializes access to the Java Beans Introspector, which is not thread safe. In addition, handles the case where
+ * the class in question is an interface, accumulating properties inherited from super-classes.
+ */
+ private synchronized ClassPropertyAdapter buildAdapter(Class forClass)
+ {
+ // In some race conditions, we may hit this method for the same class multiple times.
+ // We just let it happen, replacing the old ClassPropertyAdapter with a new one.
+
+ try
+ {
+ BeanInfo info = Introspector.getBeanInfo(forClass);
+
+ List<PropertyDescriptor> descriptors = CollectionFactory.newList();
+
+ addAll(descriptors, info.getPropertyDescriptors());
+
+ // TAP5-921 - Introspector misses interface methods not implemented in an abstract class
+ if (forClass.isInterface() || Modifier.isAbstract(forClass.getModifiers()) )
+ addPropertiesFromExtendedInterfaces(forClass, descriptors);
+
+ addPropertiesFromScala(forClass, descriptors);
+
+ return new ClassPropertyAdapterImpl(forClass, descriptors);
+ }
+ catch (Throwable ex)
+ {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private <T> void addAll(List<T> list, T[] array)
+ {
+ list.addAll(Arrays.asList(array));
+ }
+
+ private void addPropertiesFromExtendedInterfaces(Class forClass, List<PropertyDescriptor> descriptors)
+ throws IntrospectionException
+ {
+ LinkedList<Class> queue = CollectionFactory.newLinkedList();
+
+ // Seed the queue
+ addAll(queue, forClass.getInterfaces());
+
+ while (!queue.isEmpty())
+ {
+ Class c = queue.removeFirst();
+
+ BeanInfo info = Introspector.getBeanInfo(c);
+
+ // Duplicates occur and are filtered out in ClassPropertyAdapter which stores
+ // a property name to descriptor map.
+ addAll(descriptors, info.getPropertyDescriptors());
+ addAll(queue, c.getInterfaces());
+ }
+ }
+
+ private void addPropertiesFromScala(Class forClass, List<PropertyDescriptor> descriptors)
+ throws IntrospectionException
+ {
+ for (Method method : forClass.getMethods())
+ {
+ addPropertyIfScalaGetterMethod(forClass, descriptors, method);
+ }
+ }
+
+ private void addPropertyIfScalaGetterMethod(Class forClass, List<PropertyDescriptor> descriptors, Method method)
+ throws IntrospectionException
+ {
+ if (!isScalaGetterMethod(method))
+ return;
+
+ PropertyDescriptor propertyDescriptor = new PropertyDescriptor(method.getName(), forClass, method.getName(),
+ null);
+
+ // found a getter, looking for the setter now
+ try
+ {
+ Method setterMethod = findScalaSetterMethod(forClass, method);
+
+ propertyDescriptor.setWriteMethod(setterMethod);
+ }
+ catch (NoSuchMethodException e)
+ {
+ // ignore
+ }
+
+ // check if the same property was already discovered with java bean accessors
+
+ addScalaPropertyIfNoJavaBeansProperty(descriptors, propertyDescriptor, method);
+ }
+
+ private void addScalaPropertyIfNoJavaBeansProperty(List<PropertyDescriptor> descriptors,
+ PropertyDescriptor propertyDescriptor, Method getterMethod)
+ {
+ boolean found = false;
+
+ for (PropertyDescriptor currentPropertyDescriptor : descriptors)
+ {
+ if (currentPropertyDescriptor.getName().equals(getterMethod.getName()))
+ {
+ found = true;
+
+ break;
+ }
+ }
+
+ if (!found)
+ descriptors.add(propertyDescriptor);
+ }
+
+ private Method findScalaSetterMethod(Class forClass, Method getterMethod) throws NoSuchMethodException
+ {
+ return forClass.getMethod(getterMethod.getName() + "_$eq", getterMethod.getReturnType());
+ }
+
+ private boolean isScalaGetterMethod(Method method)
+ {
+ try
+ {
+ return Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0
+ && !method.getReturnType().equals(Void.TYPE)
+ && method.getDeclaringClass().getDeclaredField(method.getName()) != null;
+ }
+ catch (NoSuchFieldException ex)
+ {
+ return false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
new file mode 100644
index 0000000..97685ef
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
@@ -0,0 +1,273 @@
+// Copyright 2006-2013 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.List;
+
+public class PropertyAdapterImpl implements PropertyAdapter
+{
+ private final ClassPropertyAdapter classAdapter;
+
+ private final String name;
+
+ private final Method readMethod;
+
+ private final Method writeMethod;
+
+ private final Class type;
+
+ private final boolean castRequired;
+
+ // Synchronized by this; lazily initialized
+ private AnnotationProvider annotationProvider;
+
+ private final Field field;
+
+ private final Class declaringClass;
+
+ PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Method readMethod,
+ Method writeMethod)
+ {
+ this.classAdapter = classAdapter;
+ this.name = name;
+ this.type = type;
+
+ this.readMethod = readMethod;
+ this.writeMethod = writeMethod;
+
+ declaringClass = readMethod != null ? readMethod.getDeclaringClass() : writeMethod.getDeclaringClass();
+
+ castRequired = readMethod != null && readMethod.getReturnType() != type;
+
+ field = null;
+ }
+
+ PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Field field)
+ {
+ this.classAdapter = classAdapter;
+ this.name = name;
+ this.type = type;
+
+ this.field = field;
+
+ declaringClass = field.getDeclaringClass();
+
+ castRequired = field.getType() != type;
+
+ readMethod = null;
+ writeMethod = null;
+ }
+
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ @Override
+ public Method getReadMethod()
+ {
+ return readMethod;
+ }
+
+ @Override
+ public Class getType()
+ {
+ return type;
+ }
+
+ @Override
+ public Method getWriteMethod()
+ {
+ return writeMethod;
+ }
+
+ @Override
+ public boolean isRead()
+ {
+ return field != null || readMethod != null;
+ }
+
+ @Override
+ public boolean isUpdate()
+ {
+ return writeMethod != null || (field != null && !isFinal(field));
+ }
+
+ private boolean isFinal(Member member)
+ {
+ return Modifier.isFinal(member.getModifiers());
+ }
+
+ @Override
+ public Object get(Object instance)
+ {
+ if (field == null && readMethod == null)
+ {
+ throw new UnsupportedOperationException(String.format("Class %s does not provide an accessor ('getter') method for property '%s'.", toClassName(instance), name));
+ }
+
+ Throwable fail;
+
+ try
+ {
+ if (field == null)
+ return readMethod.invoke(instance);
+ else
+ return field.get(instance);
+ } catch (InvocationTargetException ex)
+ {
+ fail = ex.getTargetException();
+ } catch (Exception ex)
+ {
+ fail = ex;
+ }
+
+ throw new RuntimeException(ServiceMessages.readFailure(name, instance, fail), fail);
+ }
+
+ @Override
+ public void set(Object instance, Object value)
+ {
+ if (field == null && writeMethod == null)
+ {
+ throw new UnsupportedOperationException(String.format("Class %s does not provide a mutator ('setter') method for property '%s'.",
+ toClassName(instance),
+ name
+ ));
+ }
+
+ Throwable fail;
+
+ try
+ {
+ if (field == null)
+ writeMethod.invoke(instance, value);
+ else
+ field.set(instance, value);
+
+ return;
+ } catch (InvocationTargetException ex)
+ {
+ fail = ex.getTargetException();
+ } catch (Exception ex)
+ {
+ fail = ex;
+ }
+
+ throw new RuntimeException(String.format("Error updating property '%s' of %s: %s",
+ name, toClassName(instance),
+ ExceptionUtils.toMessage(fail)), fail);
+ }
+
+ private String toClassName(Object instance)
+ {
+ return instance == null ? "<null>" : instance.getClass().getName();
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return getAnnnotationProvider().getAnnotation(annotationClass);
+ }
+
+ /**
+ * Creates (as needed) the annotation provider for this property.
+ */
+ private synchronized AnnotationProvider getAnnnotationProvider()
+ {
+ if (annotationProvider == null)
+ {
+ List<AnnotationProvider> providers = CollectionFactory.newList();
+
+ if (readMethod != null)
+ providers.add(new AccessableObjectAnnotationProvider(readMethod));
+
+ if (writeMethod != null)
+ providers.add(new AccessableObjectAnnotationProvider(writeMethod));
+
+ // There's an assumption here, that the fields match the property name (we ignore case
+ // which leads to a manageable ambiguity) and that the field and the getter/setter
+ // are in the same class (i.e., that we don't have a getter exposing a protected field inherted
+ // from a base class, or some other oddity).
+
+ Class cursor = getBeanType();
+
+ out:
+ while (cursor != null)
+ {
+ for (Field f : cursor.getDeclaredFields())
+ {
+ if (f.getName().equalsIgnoreCase(name))
+ {
+ providers.add(new AccessableObjectAnnotationProvider(f));
+
+ break out;
+ }
+ }
+
+ cursor = cursor.getSuperclass();
+ }
+
+ annotationProvider = AnnotationProviderChain.create(providers);
+ }
+
+ return annotationProvider;
+ }
+
+ @Override
+ public boolean isCastRequired()
+ {
+ return castRequired;
+ }
+
+ @Override
+ public ClassPropertyAdapter getClassAdapter()
+ {
+ return classAdapter;
+ }
+
+ @Override
+ public Class getBeanType()
+ {
+ return classAdapter.getBeanType();
+ }
+
+ @Override
+ public boolean isField()
+ {
+ return field != null;
+ }
+
+ @Override
+ public Field getField()
+ {
+ return field;
+ }
+
+ @Override
+ public Class getDeclaringClass()
+ {
+ return declaringClass;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/build.gradle
----------------------------------------------------------------------
diff --git a/commons/build.gradle b/commons/build.gradle
index 76850ef..98ae8bf 100644
--- a/commons/build.gradle
+++ b/commons/build.gradle
@@ -10,6 +10,7 @@ buildDir = 'target/gradle-build'
dependencies {
compile project(":plastic")
compile project(":tapestry5-annotations")
+ compile project(":tapestry-func")
}
jar {
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
new file mode 100644
index 0000000..fae9ab8
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
@@ -0,0 +1,54 @@
+// Copyright 2009, 2012 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 org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.services.ComponentClasses;
+import org.apache.tapestry5.services.InvalidationEventHub;
+
+import javax.annotation.PostConstruct;
+
+import java.util.Map;
+
+public class StringInternerImpl implements StringInterner
+{
+ private final Map<String, String> cache = CollectionFactory.newConcurrentMap();
+
+ @PostConstruct
+ public void setupInvalidation(@ComponentClasses InvalidationEventHub hub)
+ {
+ hub.clearOnInvalidation(cache);
+ }
+
+ public String intern(String string)
+ {
+ String result = cache.get(string);
+
+ // Not yet in the cache? Add it.
+
+ if (result == null)
+ {
+ cache.put(string, string);
+ result = string;
+ }
+
+ return result;
+ }
+
+ public String format(String format, Object... arguments)
+ {
+ return intern(String.format(format, arguments));
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java b/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
new file mode 100644
index 0000000..03814f5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
@@ -0,0 +1,53 @@
+// Copyright 2006, 2008, 2009 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.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * This implementation is used for un-ordered configuration data.
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
+ * must be compatible with the type.
+ */
+public interface Configuration<T>
+{
+ /**
+ * Adds an object to the service's contribution.
+ *
+ * @param object
+ * to add to the service's configuration
+ */
+ void add(T object);
+
+ /**
+ * Automatically instantiates an instance of the class, with dependencies injected, and adds it to the
+ * configuration. When the configuration type is an interface and the class to be contributed is a local file,
+ * then a reloadable proxy for the class will be created and contributed.
+ *
+ * @param clazz
+ * what class to instantiate
+ * @since 5.1.0.0
+ */
+ void addInstance(Class<? extends T> clazz);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java b/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
new file mode 100644
index 0000000..47c6026
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
@@ -0,0 +1,81 @@
+// Copyright 2006, 2008, 2009, 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.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
+ * must be compatible with the type.
+ */
+public interface MappedConfiguration<K, V>
+{
+
+ /**
+ * Adds a keyed object to the service's contribution.
+ *
+ * @param key
+ * unique id for the value
+ * @param value
+ * to contribute
+ * @throws IllegalArgumentException
+ * if key is not unique
+ */
+ void add(K key, V value);
+
+ /**
+ * Overrides an existing contribution by its key.
+ *
+ * @param key
+ * unique id of value to override
+ * @param value
+ * new value, or null to remove the key entirely
+ * @since 5.1.0.0
+ */
+ void override(K key, V value);
+
+ /**
+ * Adds a keyed object as an instantiated instance (with dependencies injected) of a class. When the value
+ * type is an interface and the class to be contributed is a local file,
+ * then a reloadable proxy for the value class will be created and contributed.
+ *
+ * @param key
+ * unique id for the value
+ * @param clazz
+ * class to instantiate and contribute
+ * @since 5.1.0.0
+ */
+ void addInstance(K key, Class<? extends V> clazz);
+
+ /**
+ * Overrides an existing contribution with a new instance. When the value
+ * type is an interface and the class to be contributed is a local file,
+ * then a reloadable proxy for the value class will be created and contributed.
+ *
+ * @param key
+ * unique id of value to override
+ * @param clazz
+ * class to instantiate as override
+ */
+ void overrideInstance(K key, Class<? extends V> clazz);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java b/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
new file mode 100644
index 0000000..9151381
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
@@ -0,0 +1,84 @@
+// Copyright 2006, 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.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
+ * must be compatible with the type, or be {@linkplain org.apache.tapestry5.ioc.services.TypeCoercer coercable} to the type.
+ *
+ * @see org.apache.tapestry5.ioc.annotations.Contribute
+ * @see org.apache.tapestry5.ioc.annotations.UsesConfiguration
+ */
+public interface OrderedConfiguration<T>
+{
+ /**
+ * Adds an ordered object to a service's contribution. Each object has an id (which must be unique). Optionally,
+ * pre-requisites (a list of ids that must precede this object) and post-requisites (ids that must follow) can be
+ * provided.
+ * <p/>
+ * <p>If no constraints are supplied, then an implicit constraint is supplied: after the previously
+ * contributed id <em>within the same contribution method</em>.
+ *
+ * @param id a unique id for the object; the id will be fully qualified with the contributing module's id
+ * @param constraints used to order the object relative to other contributed objects
+ * @param object to add to the service's configuration
+ */
+ void add(String id, T object, String... constraints);
+
+ /**
+ * Overrides a normally contributed object. Each override must match a single normally contributed object.
+ *
+ * @param id identifies object to override
+ * @param object overriding object (may be null)
+ * @param constraints constraints for the overridden object, replacing constraints for the original object (even if
+ * omitted, in which case the override object will have no ordering constraints)
+ * @since 5.1.0.0
+ */
+ void override(String id, T object, String... constraints);
+
+ /**
+ * Adds an ordered object by instantiating (with dependencies) the indicated class. When the configuration type is
+ * an interface and the class to be contributed is a local file,
+ * then a reloadable proxy for the class will be created and contributed.
+ *
+ * @param id of contribution (used for ordering)
+ * @param clazz class to instantiate
+ * @param constraints used to order the object relative to other contributed objects
+ * @since 5.1.0.0
+ */
+ void addInstance(String id, Class<? extends T> clazz, String... constraints);
+
+ /**
+ * Instantiates an object and adds it as an override. When the configuration type is an interface and the class to
+ * be contributed is a local file, then a reloadable proxy for the class will be created and contributed.
+ *
+ * @param id of object to override
+ * @param clazz to instantiate
+ * @param constraints constraints for the overridden object, replacing constraints for the original object (even if
+ * omitted, in which case the override object will have no ordering constraints)
+ * @since 5.1.0.0
+ */
+ void overrideInstance(String id, Class<? extends T> clazz, String... constraints);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
new file mode 100644
index 0000000..f7bde31
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
@@ -0,0 +1,342 @@
+// Copyright 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.ioc.internal;
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.tapestry5.func.Flow;
+import org.apache.tapestry5.ioc.Configuration;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.ioc.util.TimeInterval;
+
+/**
+ * Class that provides Tapestry-IoC's basic type coercions.
+ * @see TypeCoercer
+ * @see Coercion
+ */
+public class BasicTypeCoercions
+{
+ /**
+ * Provides the basic type coercions to a {@link Configuration} instance.
+ */
+ public static void provideBasicTypeCoercions(Configuration<CoercionTuple> configuration)
+ {
+ add(configuration, Object.class, String.class, new Coercion<Object, String>()
+ {
+ @Override
+ public String coerce(Object input)
+ {
+ return input.toString();
+ }
+ });
+
+ add(configuration, Object.class, Boolean.class, new Coercion<Object, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Object input)
+ {
+ return input != null;
+ }
+ });
+
+ add(configuration, String.class, Double.class, new Coercion<String, Double>()
+ {
+ @Override
+ public Double coerce(String input)
+ {
+ return new Double(input);
+ }
+ });
+
+ // String to BigDecimal is important, as String->Double->BigDecimal would lose
+ // precision.
+
+ add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>()
+ {
+ @Override
+ public BigDecimal coerce(String input)
+ {
+ return new BigDecimal(input);
+ }
+ });
+
+ add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>()
+ {
+ @Override
+ public Double coerce(BigDecimal input)
+ {
+ return input.doubleValue();
+ }
+ });
+
+ add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>()
+ {
+ @Override
+ public BigInteger coerce(String input)
+ {
+ return new BigInteger(input);
+ }
+ });
+
+ add(configuration, String.class, Long.class, new Coercion<String, Long>()
+ {
+ @Override
+ public Long coerce(String input)
+ {
+ return new Long(input);
+ }
+ });
+
+ add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
+ {
+ @Override
+ public Byte coerce(Long input)
+ {
+ return input.byteValue();
+ }
+ });
+
+ add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
+ {
+ @Override
+ public Short coerce(Long input)
+ {
+ return input.shortValue();
+ }
+ });
+
+ add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>()
+ {
+ @Override
+ public Integer coerce(Long input)
+ {
+ return input.intValue();
+ }
+ });
+
+ add(configuration, Number.class, Long.class, new Coercion<Number, Long>()
+ {
+ @Override
+ public Long coerce(Number input)
+ {
+ return input.longValue();
+ }
+ });
+
+ add(configuration, Double.class, Float.class, new Coercion<Double, Float>()
+ {
+ @Override
+ public Float coerce(Double input)
+ {
+ return input.floatValue();
+ }
+ });
+
+ add(configuration, Long.class, Double.class, new Coercion<Long, Double>()
+ {
+ @Override
+ public Double coerce(Long input)
+ {
+ return input.doubleValue();
+ }
+ });
+
+ add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>()
+ {
+ @Override
+ public Boolean coerce(String input)
+ {
+ String trimmed = input == null ? "" : input.trim();
+
+ if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
+ return false;
+
+ // Any non-blank string but "false"
+
+ return true;
+ }
+ });
+
+ add(configuration, Number.class, Boolean.class, new Coercion<Number, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Number input)
+ {
+ return input.longValue() != 0;
+ }
+ });
+
+ add(configuration, Void.class, Boolean.class, new Coercion<Void, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Void input)
+ {
+ return false;
+ }
+ });
+
+ add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Collection input)
+ {
+ return !input.isEmpty();
+ }
+ });
+
+ add(configuration, Object.class, List.class, new Coercion<Object, List>()
+ {
+ @Override
+ public List coerce(Object input)
+ {
+ return Collections.singletonList(input);
+ }
+ });
+
+ add(configuration, Object[].class, List.class, new Coercion<Object[], List>()
+ {
+ @Override
+ public List coerce(Object[] input)
+ {
+ return Arrays.asList(input);
+ }
+ });
+
+ add(configuration, Object[].class, Boolean.class, new Coercion<Object[], Boolean>()
+ {
+ @Override
+ public Boolean coerce(Object[] input)
+ {
+ return input != null && input.length > 0;
+ }
+ });
+
+ add(configuration, Float.class, Double.class, new Coercion<Float, Double>()
+ {
+ @Override
+ public Double coerce(Float input)
+ {
+ return input.doubleValue();
+ }
+ });
+
+ Coercion primitiveArrayCoercion = new Coercion<Object, List>()
+ {
+ @Override
+ public List<Object> coerce(Object input)
+ {
+ int length = Array.getLength(input);
+ Object[] array = new Object[length];
+ for (int i = 0; i < length; i++)
+ {
+ array[i] = Array.get(input, i);
+ }
+ return Arrays.asList(array);
+ }
+ };
+
+ add(configuration, byte[].class, List.class, primitiveArrayCoercion);
+ add(configuration, short[].class, List.class, primitiveArrayCoercion);
+ add(configuration, int[].class, List.class, primitiveArrayCoercion);
+ add(configuration, long[].class, List.class, primitiveArrayCoercion);
+ add(configuration, float[].class, List.class, primitiveArrayCoercion);
+ add(configuration, double[].class, List.class, primitiveArrayCoercion);
+ add(configuration, char[].class, List.class, primitiveArrayCoercion);
+ add(configuration, boolean[].class, List.class, primitiveArrayCoercion);
+
+ add(configuration, String.class, File.class, new Coercion<String, File>()
+ {
+ @Override
+ public File coerce(String input)
+ {
+ return new File(input);
+ }
+ });
+
+ add(configuration, String.class, TimeInterval.class, new Coercion<String, TimeInterval>()
+ {
+ @Override
+ public TimeInterval coerce(String input)
+ {
+ return new TimeInterval(input);
+ }
+ });
+
+ add(configuration, TimeInterval.class, Long.class, new Coercion<TimeInterval, Long>()
+ {
+ @Override
+ public Long coerce(TimeInterval input)
+ {
+ return input.milliseconds();
+ }
+ });
+
+ add(configuration, Object.class, Object[].class, new Coercion<Object, Object[]>()
+ {
+ @Override
+ public Object[] coerce(Object input)
+ {
+ return new Object[]
+ {input};
+ }
+ });
+
+ add(configuration, Collection.class, Object[].class, new Coercion<Collection, Object[]>()
+ {
+ @Override
+ public Object[] coerce(Collection input)
+ {
+ return input.toArray();
+ }
+ });
+
+ configuration.add(CoercionTuple.create(Flow.class, List.class, new Coercion<Flow, List>()
+ {
+ @Override
+ public List coerce(Flow input)
+ {
+ return input.toList();
+ }
+ }));
+
+ configuration.add(CoercionTuple.create(Flow.class, Boolean.class, new Coercion<Flow, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Flow input)
+ {
+ return !input.isEmpty();
+ }
+ }));
+
+
+ }
+
+ private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
+ Class<T> targetType, Coercion<S, T> coercion)
+ {
+ configuration.add(CoercionTuple.create(sourceType, targetType, coercion));
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
new file mode 100644
index 0000000..2acfd0d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
@@ -0,0 +1,46 @@
+// Copyright 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+
+/**
+ * Provides access to annotations of an accessable object such as a {@link java.lang.reflect.Method} or {@link
+ * java.lang.reflect.Field}.
+ */
+public class AccessableObjectAnnotationProvider implements AnnotationProvider
+{
+ private final AccessibleObject object;
+
+ public AccessableObjectAnnotationProvider(AccessibleObject object)
+ {
+ this.object = object;
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return object.getAnnotation(annotationClass);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("AnnotationProvider[%s]", object);
+ }
+}
[10/15] tapestry-5 git commit: Third pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
Third pass creating the BeanModel and Commons packages.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/dd958465
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/dd958465
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/dd958465
Branch: refs/heads/beanmodel-split
Commit: dd9584659823c87f014a1cf57c7be592eedfa4c6
Parents: c9e97d6
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 17:33:54 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 17:33:54 2014 -0200
----------------------------------------------------------------------
.../tapestry5/internal/BeanModelUtils.java | 145 ------------
.../internal/InternalBeanModelUtils.java | 145 ++++++++++++
.../internal/beaneditor/BeanModelUtils.java | 120 ++++++++++
.../internal/beaneditor/PropertyModelImpl.java | 6 +-
.../internal/services/BeanModelSourceImpl.java | 222 +++++++++++++++++++
.../services/PropertyConduitSourceImpl.java | 4 +-
.../tapestry5/services/DataTypeAnalyzer.java | 48 ++++
.../internal/TapestryInternalUtils.java | 8 +-
.../internal/beaneditor/BeanModelUtils.java | 119 ----------
.../internal/services/BeanModelSourceImpl.java | 222 -------------------
.../tapestry5/services/DataTypeAnalyzer.java | 48 ----
.../annotations/UsesMappedConfiguration.java | 41 ----
.../annotations/UsesOrderedConfiguration.java | 33 ---
.../ioc/internal/util/InternalUtils.java | 6 +-
.../annotations/UsesMappedConfiguration.java | 41 ++++
.../annotations/UsesOrderedConfiguration.java | 33 +++
16 files changed, 621 insertions(+), 620 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
deleted file mode 100644
index 08cb88a..0000000
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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.internal;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.regex.Pattern;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
-
-/**
- * Some methods broken off tapestry-core's InternalUtils to avoid bringing the whole class
- * plus its multiple dependencies to the BeanModel package.
- */
-public class BeanModelUtils {
-
- public static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
-
- /**
- * @since 5.3
- */
- private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-
-
- /**
- * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
- * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
- * underscore).
- *
- * @param expression a property expression
- * @return the expression with punctuation removed
- */
- public static String extractIdFromPropertyExpression(String expression)
- {
- return replace(expression, NON_WORD_PATTERN, "");
- }
-
- public static String replace(String input, Pattern pattern, String replacement)
- {
- return pattern.matcher(input).replaceAll(replacement);
- }
-
- /**
- * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
- * user presentable form.
- */
- public static String defaultLabel(String id, Messages messages, String propertyExpression)
- {
- String key = id + "-label";
-
- if (messages.contains(key))
- return messages.get(key);
-
- return toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
- }
-
- /**
- * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
- * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
- * following word), thus "user_id" also becomes "User Id".
- */
- public static String toUserPresentable(String id)
- {
- StringBuilder builder = new StringBuilder(id.length() * 2);
-
- char[] chars = id.toCharArray();
- boolean postSpace = true;
- boolean upcaseNext = true;
-
- for (char ch : chars)
- {
- if (upcaseNext)
- {
- builder.append(Character.toUpperCase(ch));
- upcaseNext = false;
-
- continue;
- }
-
- if (ch == '_')
- {
- builder.append(' ');
- upcaseNext = true;
- continue;
- }
-
- boolean upperCase = Character.isUpperCase(ch);
-
- if (upperCase && !postSpace)
- builder.append(' ');
-
- builder.append(ch);
-
- postSpace = upperCase;
- }
-
- return builder.toString();
- }
-
- /**
- * @since 5.3
- */
- public static AnnotationProvider toAnnotationProvider(final Class element)
- {
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationClass.cast(element.getAnnotation(annotationClass));
- }
- };
- }
-
- public static AnnotationProvider toAnnotationProvider(final Method element)
- {
- if (element == null)
- return NULL_ANNOTATION_PROVIDER;
-
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return element.getAnnotation(annotationClass);
- }
- };
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
new file mode 100644
index 0000000..88f4c7f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
@@ -0,0 +1,145 @@
+// 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.internal;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+
+/**
+ * Some methods broken off tapestry-core's InternalUtils to avoid bringing the whole class
+ * plus its multiple dependencies to the BeanModel package.
+ */
+public class InternalBeanModelUtils {
+
+ public static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+ /**
+ * @since 5.3
+ */
+ private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
+
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
new file mode 100644
index 0000000..154ee79
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
@@ -0,0 +1,120 @@
+// 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.beaneditor;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+
+/**
+ * Utilities used in a few places to modify an existing {@link BeanModel}.
+ */
+public final class BeanModelUtils
+{
+
+ final private static String[] EMPTY_STRING_ARRAY = new String[0];
+
+ /**
+ * Performs standard set of modifications to a {@link org.apache.tapestry5.beaneditor.BeanModel}
+ * . First new
+ * properties may be added, then properties removed, then properties reordered.
+ *
+ * @param model to modifiy
+ * @param addPropertyNames comma seperated list of property names to add, or null
+ * @param includePropertyNames comma seperated list of property names to include
+ * @param excludePropertyNames comma seperated list of property names to exclude, or null
+ * @param reorderPropertyNames comma seperated list of property names to reorder, or null
+ */
+ public static void modify(BeanModel model, String addPropertyNames,
+ String includePropertyNames, String excludePropertyNames, String reorderPropertyNames)
+ {
+ if (addPropertyNames != null)
+ add(model, addPropertyNames);
+
+ if (includePropertyNames != null)
+ include(model, join(includePropertyNames, addPropertyNames));
+
+ if (excludePropertyNames != null)
+ exclude(model, excludePropertyNames);
+
+ if (reorderPropertyNames != null)
+ reorder(model, reorderPropertyNames);
+ }
+
+ private static final String join(String firstList, String optionalSecondList)
+ {
+ if (InternalStringUtils.isBlank(optionalSecondList))
+ return firstList;
+
+ return firstList + "," + optionalSecondList;
+ }
+
+ /**
+ * Adds empty properties to the bean model. New properties are added with a <em>null</em>
+ * {@link org.apache.tapestry5.PropertyConduit}. `
+ *
+ * @param model to be modified
+ * @param propertyNames comma-separated list of property names
+ * @see BeanModel#addEmpty(String)
+ */
+ public static void add(BeanModel model, String propertyNames)
+ {
+ for (String name : split(propertyNames))
+ {
+ model.addEmpty(name);
+ }
+ }
+
+ /**
+ * Removes properties from the bean model.
+ *
+ * @param model
+ * @param propertyNames comma-separated list of property names
+ * @see BeanModel#exclude(String...)
+ */
+ public static void exclude(BeanModel model, String propertyNames)
+ {
+ model.exclude(split(propertyNames));
+ }
+
+ /**
+ * Selects a subset of the properties to keep, and reorders them.
+ */
+ public static void include(BeanModel model, String propertyNames)
+ {
+ model.include(split(propertyNames));
+ }
+
+ /**
+ * Reorders properties within the bean model.
+ *
+ * @param model
+ * @param propertyNames comma-separated list of property names
+ * @see BeanModel#reorder(String...)
+ */
+ public static void reorder(BeanModel model, String propertyNames)
+ {
+ model.reorder(split(propertyNames));
+ }
+
+ static String[] split(String propertyNames)
+ {
+ String trimmed = propertyNames.trim();
+
+ if (trimmed.length() == 0)
+ return EMPTY_STRING_ARRAY;
+
+ return trimmed.split("\\s*,\\s*");
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/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
index b21e5bb..4632818 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -20,7 +20,7 @@ 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.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
this.name = name;
this.conduit = conduit;
- id = BeanModelUtils.extractIdFromPropertyExpression(name);
+ id = InternalBeanModelUtils.extractIdFromPropertyExpression(name);
- label = BeanModelUtils.defaultLabel(id, messages, name);
+ label = InternalBeanModelUtils.defaultLabel(id, messages, name);
// TAP5-2305
if (conduit != null)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
new file mode 100644
index 0000000..bb20de0
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
@@ -0,0 +1,222 @@
+// 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.services;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.beaneditor.NonVisual;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
+import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
+import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.annotations.Primary;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.services.BeanModelSource;
+import org.apache.tapestry5.services.ComponentLayer;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.List;
+
+public class BeanModelSourceImpl implements BeanModelSource
+{
+ private final TypeCoercer typeCoercer;
+
+ private final PropertyAccess propertyAccess;
+
+ private final PropertyConduitSource propertyConduitSource;
+
+ private final PlasticProxyFactory proxyFactory;
+
+ private final DataTypeAnalyzer dataTypeAnalyzer;
+
+ private final ObjectLocator locator;
+
+ private static class PropertyOrder implements Comparable<PropertyOrder>
+ {
+ final String propertyName;
+
+ final int classDepth;
+
+ final int sortKey;
+
+ public PropertyOrder(final String propertyName, int classDepth, int sortKey)
+ {
+ this.propertyName = propertyName;
+ this.classDepth = classDepth;
+ this.sortKey = sortKey;
+ }
+
+ public int compareTo(PropertyOrder o)
+ {
+ int result = classDepth - o.classDepth;
+
+ if (result == 0)
+ result = sortKey - o.sortKey;
+
+ if (result == 0)
+ result = propertyName.compareTo(o.propertyName);
+
+ return result;
+ }
+ }
+
+ /**
+ * @param classAdapter defines the bean that contains the properties
+ * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
+ */
+ private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
+ {
+ List<PropertyOrder> properties = CollectionFactory.newList();
+
+ for (String name : propertyNames)
+ {
+ PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
+
+ Method readMethod = pa.getReadMethod();
+
+ Location location = readMethod == null ? null : proxyFactory.getMethodLocation(readMethod);
+
+ int line = location == null ? -1 : location.getLine();
+
+ properties.add(new PropertyOrder(name, computeDepth(pa), line));
+ }
+
+ Collections.sort(properties);
+
+ propertyNames.clear();
+
+ for (PropertyOrder po : properties)
+ {
+ propertyNames.add(po.propertyName);
+ }
+ }
+
+ private static int computeDepth(PropertyAdapter pa)
+ {
+ int depth = 0;
+ Class c = pa.getDeclaringClass();
+
+ // When the method originates in an interface, the parent may be null, not Object.
+
+ while (c != null && c != Object.class)
+ {
+ depth++;
+ c = c.getSuperclass();
+ }
+
+ return depth;
+ }
+
+ public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
+ PropertyConduitSource propertyConduitSource,
+ @ComponentLayer
+ PlasticProxyFactory proxyFactory,
+ @Primary
+ DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
+ {
+ this.typeCoercer = typeCoercer;
+ this.propertyAccess = propertyAccess;
+ this.propertyConduitSource = propertyConduitSource;
+ this.proxyFactory = proxyFactory;
+ this.dataTypeAnalyzer = dataTypeAnalyzer;
+ this.locator = locator;
+ }
+
+ public <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages)
+ {
+ return create(beanClass, false, messages);
+ }
+
+ public <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages)
+ {
+ return create(beanClass, true, messages);
+ }
+
+ public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
+ {
+ assert beanClass != null;
+ assert messages != null;
+ ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
+
+ BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
+
+ for (final String propertyName : adapter.getPropertyNames())
+ {
+ PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);
+
+ if (!pa.isRead())
+ {
+ continue;
+ }
+
+ if (isStaticFieldProperty(pa))
+ {
+ continue;
+ }
+
+ if (pa.getAnnotation(NonVisual.class) != null)
+ {
+ continue;
+ }
+
+ if (filterReadOnlyProperties && !pa.isUpdate())
+ {
+ continue;
+ }
+
+ final String dataType = dataTypeAnalyzer.identifyDataType(pa);
+
+ // If an unregistered type, then ignore the property.
+
+ if (dataType == null)
+ {
+ continue;
+ }
+
+ model.add(propertyName).dataType(dataType);
+ }
+
+ // First, order the properties based on the location of the getter method
+ // within the class.
+
+ List<String> propertyNames = model.getPropertyNames();
+
+ orderProperties(adapter, propertyNames);
+
+ model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
+
+ // Next, check for an annotation with specific ordering information.
+
+ ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
+
+ if (reorderAnnotation != null)
+ {
+ BeanModelUtils.reorder(model, reorderAnnotation.value());
+ }
+
+ return model;
+ }
+
+ private boolean isStaticFieldProperty(PropertyAdapter adapter)
+ {
+ return adapter.isField() && Modifier.isStatic(adapter.getField().getModifiers());
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 83f67fa..4ce072e 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -19,7 +19,7 @@ import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.Tree;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.internal.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.internal.InternalPropertyConduit;
import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -1260,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
Type returnType = GenericsUtils.extractActualType(activeType, method);
- return new Term(returnType, toUniqueId(method), BeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+ return new Term(returnType, toUniqueId(method), InternalBeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java b/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
new file mode 100644
index 0000000..ba7e995
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
@@ -0,0 +1,48 @@
+// Copyright 2007, 2008, 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.services;
+
+import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
+import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+
+/**
+ * Used by {@link BeanModelSource} to identify the type of data associated with a particular property (represented as a
+ * {@link PropertyAdapter}). The data type is a string used to determine what kind of interface to use for displaying
+ * the value of the property, or what kind of interface to use for editing the value of the property. Common property
+ * types are "text", "enum", "checkbox", but the list is extensible.
+ * <p/>
+ * Different strategies for identifying the data type are encapsulated in the DataTypeAnalyzer service, forming a
+ * chain of command.
+ * <p/>
+ * The DefaultDataTypeAnalyzer service maps property types to data type names.
+ * <p/>
+ * The DataTypeAnalyzer service is an extensible {@linkplain org.apache.tapestry5.ioc.services.ChainBuilder chain of
+ * command}), that (by default) includes {@link org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer} and
+ * the {@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} service (ordered last). It uses an ordered configuration.
+ *
+ * @see org.apache.tapestry5.corelib.components.Grid
+ * @see org.apache.tapestry5.corelib.components.BeanEditForm
+ * @see BeanBlockSource
+ */
+@UsesOrderedConfiguration(DataTypeAnalyzer.class)
+@UsesMappedConfiguration(key = Class.class, value = String.class)
+public interface DataTypeAnalyzer
+{
+ /**
+ * Identifies the data type, if known, or returns null if not known.
+ */
+ String identifyDataType(PropertyAdapter adapter);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index aba7225..e69377f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
*/
public static String toUserPresentable(String id)
{
- return BeanModelUtils.toUserPresentable(id);
+ return InternalBeanModelUtils.toUserPresentable(id);
}
public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
*/
public static String extractIdFromPropertyExpression(String expression)
{
- return BeanModelUtils.extractIdFromPropertyExpression(expression);
+ return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
}
/**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
*/
public static String defaultLabel(String id, Messages messages, String propertyExpression)
{
- return BeanModelUtils.defaultLabel(id, messages, propertyExpression);
+ return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
}
/**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
private static String replace(String input, Pattern pattern, String replacement)
{
- return BeanModelUtils.replace(input, pattern, replacement);
+ return InternalBeanModelUtils.replace(input, pattern, replacement);
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
deleted file mode 100644
index 6a79b6e..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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.beaneditor;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.internal.InternalConstants;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-/**
- * Utilities used in a few places to modify an existing {@link BeanModel}.
- */
-public final class BeanModelUtils
-{
-
- /**
- * Performs standard set of modifications to a {@link org.apache.tapestry5.beaneditor.BeanModel}
- * . First new
- * properties may be added, then properties removed, then properties reordered.
- *
- * @param model to modifiy
- * @param addPropertyNames comma seperated list of property names to add, or null
- * @param includePropertyNames comma seperated list of property names to include
- * @param excludePropertyNames comma seperated list of property names to exclude, or null
- * @param reorderPropertyNames comma seperated list of property names to reorder, or null
- */
- public static void modify(BeanModel model, String addPropertyNames,
- String includePropertyNames, String excludePropertyNames, String reorderPropertyNames)
- {
- if (addPropertyNames != null)
- add(model, addPropertyNames);
-
- if (includePropertyNames != null)
- include(model, join(includePropertyNames, addPropertyNames));
-
- if (excludePropertyNames != null)
- exclude(model, excludePropertyNames);
-
- if (reorderPropertyNames != null)
- reorder(model, reorderPropertyNames);
- }
-
- private static final String join(String firstList, String optionalSecondList)
- {
- if (InternalUtils.isBlank(optionalSecondList))
- return firstList;
-
- return firstList + "," + optionalSecondList;
- }
-
- /**
- * Adds empty properties to the bean model. New properties are added with a <em>null</em>
- * {@link org.apache.tapestry5.PropertyConduit}. `
- *
- * @param model to be modified
- * @param propertyNames comma-separated list of property names
- * @see BeanModel#addEmpty(String)
- */
- public static void add(BeanModel model, String propertyNames)
- {
- for (String name : split(propertyNames))
- {
- model.addEmpty(name);
- }
- }
-
- /**
- * Removes properties from the bean model.
- *
- * @param model
- * @param propertyNames comma-separated list of property names
- * @see BeanModel#exclude(String...)
- */
- public static void exclude(BeanModel model, String propertyNames)
- {
- model.exclude(split(propertyNames));
- }
-
- /**
- * Selects a subset of the properties to keep, and reorders them.
- */
- public static void include(BeanModel model, String propertyNames)
- {
- model.include(split(propertyNames));
- }
-
- /**
- * Reorders properties within the bean model.
- *
- * @param model
- * @param propertyNames comma-separated list of property names
- * @see BeanModel#reorder(String...)
- */
- public static void reorder(BeanModel model, String propertyNames)
- {
- model.reorder(split(propertyNames));
- }
-
- static String[] split(String propertyNames)
- {
- String trimmed = propertyNames.trim();
-
- if (trimmed.length() == 0)
- return InternalConstants.EMPTY_STRING_ARRAY;
-
- return trimmed.split("\\s*,\\s*");
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
deleted file mode 100644
index bb20de0..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
+++ /dev/null
@@ -1,222 +0,0 @@
-// 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.services;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.beaneditor.NonVisual;
-import org.apache.tapestry5.beaneditor.ReorderProperties;
-import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
-import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.ObjectLocator;
-import org.apache.tapestry5.ioc.annotations.Primary;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.services.BeanModelSource;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.DataTypeAnalyzer;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.List;
-
-public class BeanModelSourceImpl implements BeanModelSource
-{
- private final TypeCoercer typeCoercer;
-
- private final PropertyAccess propertyAccess;
-
- private final PropertyConduitSource propertyConduitSource;
-
- private final PlasticProxyFactory proxyFactory;
-
- private final DataTypeAnalyzer dataTypeAnalyzer;
-
- private final ObjectLocator locator;
-
- private static class PropertyOrder implements Comparable<PropertyOrder>
- {
- final String propertyName;
-
- final int classDepth;
-
- final int sortKey;
-
- public PropertyOrder(final String propertyName, int classDepth, int sortKey)
- {
- this.propertyName = propertyName;
- this.classDepth = classDepth;
- this.sortKey = sortKey;
- }
-
- public int compareTo(PropertyOrder o)
- {
- int result = classDepth - o.classDepth;
-
- if (result == 0)
- result = sortKey - o.sortKey;
-
- if (result == 0)
- result = propertyName.compareTo(o.propertyName);
-
- return result;
- }
- }
-
- /**
- * @param classAdapter defines the bean that contains the properties
- * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
- */
- private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
- {
- List<PropertyOrder> properties = CollectionFactory.newList();
-
- for (String name : propertyNames)
- {
- PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
-
- Method readMethod = pa.getReadMethod();
-
- Location location = readMethod == null ? null : proxyFactory.getMethodLocation(readMethod);
-
- int line = location == null ? -1 : location.getLine();
-
- properties.add(new PropertyOrder(name, computeDepth(pa), line));
- }
-
- Collections.sort(properties);
-
- propertyNames.clear();
-
- for (PropertyOrder po : properties)
- {
- propertyNames.add(po.propertyName);
- }
- }
-
- private static int computeDepth(PropertyAdapter pa)
- {
- int depth = 0;
- Class c = pa.getDeclaringClass();
-
- // When the method originates in an interface, the parent may be null, not Object.
-
- while (c != null && c != Object.class)
- {
- depth++;
- c = c.getSuperclass();
- }
-
- return depth;
- }
-
- public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
- PropertyConduitSource propertyConduitSource,
- @ComponentLayer
- PlasticProxyFactory proxyFactory,
- @Primary
- DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
- {
- this.typeCoercer = typeCoercer;
- this.propertyAccess = propertyAccess;
- this.propertyConduitSource = propertyConduitSource;
- this.proxyFactory = proxyFactory;
- this.dataTypeAnalyzer = dataTypeAnalyzer;
- this.locator = locator;
- }
-
- public <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages)
- {
- return create(beanClass, false, messages);
- }
-
- public <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages)
- {
- return create(beanClass, true, messages);
- }
-
- public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
- {
- assert beanClass != null;
- assert messages != null;
- ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
-
- BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
-
- for (final String propertyName : adapter.getPropertyNames())
- {
- PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);
-
- if (!pa.isRead())
- {
- continue;
- }
-
- if (isStaticFieldProperty(pa))
- {
- continue;
- }
-
- if (pa.getAnnotation(NonVisual.class) != null)
- {
- continue;
- }
-
- if (filterReadOnlyProperties && !pa.isUpdate())
- {
- continue;
- }
-
- final String dataType = dataTypeAnalyzer.identifyDataType(pa);
-
- // If an unregistered type, then ignore the property.
-
- if (dataType == null)
- {
- continue;
- }
-
- model.add(propertyName).dataType(dataType);
- }
-
- // First, order the properties based on the location of the getter method
- // within the class.
-
- List<String> propertyNames = model.getPropertyNames();
-
- orderProperties(adapter, propertyNames);
-
- model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
-
- // Next, check for an annotation with specific ordering information.
-
- ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
-
- if (reorderAnnotation != null)
- {
- BeanModelUtils.reorder(model, reorderAnnotation.value());
- }
-
- return model;
- }
-
- private boolean isStaticFieldProperty(PropertyAdapter adapter)
- {
- return adapter.isField() && Modifier.isStatic(adapter.getField().getModifiers());
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
deleted file mode 100644
index ba7e995..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2007, 2008, 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.services;
-
-import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
-import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-
-/**
- * Used by {@link BeanModelSource} to identify the type of data associated with a particular property (represented as a
- * {@link PropertyAdapter}). The data type is a string used to determine what kind of interface to use for displaying
- * the value of the property, or what kind of interface to use for editing the value of the property. Common property
- * types are "text", "enum", "checkbox", but the list is extensible.
- * <p/>
- * Different strategies for identifying the data type are encapsulated in the DataTypeAnalyzer service, forming a
- * chain of command.
- * <p/>
- * The DefaultDataTypeAnalyzer service maps property types to data type names.
- * <p/>
- * The DataTypeAnalyzer service is an extensible {@linkplain org.apache.tapestry5.ioc.services.ChainBuilder chain of
- * command}), that (by default) includes {@link org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer} and
- * the {@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} service (ordered last). It uses an ordered configuration.
- *
- * @see org.apache.tapestry5.corelib.components.Grid
- * @see org.apache.tapestry5.corelib.components.BeanEditForm
- * @see BeanBlockSource
- */
-@UsesOrderedConfiguration(DataTypeAnalyzer.class)
-@UsesMappedConfiguration(key = Class.class, value = String.class)
-public interface DataTypeAnalyzer
-{
- /**
- * Identifies the data type, if known, or returns null if not known.
- */
- String identifyDataType(PropertyAdapter adapter);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
deleted file mode 100644
index a336365..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2008, 2009 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.ioc.annotations;
-
-import java.lang.annotation.*;
-
-/**
- * A documentation-only interface placed on service interfaces for services which have a {@linkplain
- * org.apache.tapestry5.ioc.MappedConfiguration mapped configuration}, to identify the type of key (often, a String),
- * and type ofcontribution.
- * <p/>
- * Remember that when the key type is String, the map will be case-insensitive.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesMappedConfiguration
-{
- /**
- * The type of key used to identify contribution values.
- */
- Class key() default String.class;
-
- /**
- * The type of object which may be contributed into the service's configuration.
- */
- Class value();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
deleted file mode 100644
index 7c608f6..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2008, 2009 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.ioc.annotations;
-
-import java.lang.annotation.*;
-
-/**
- * A documentation-only interface placed on service interfaces for services which have an {@linkplain
- * org.apache.tapestry5.ioc.OrderedConfiguration ordered configuration}, to identify the type of contribution.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesOrderedConfiguration
-{
- /**
- * The type of object which may be contributed into the service's configuration.
- */
- Class value();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index a40f984..8f1f7b6 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.ioc.internal.util;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.func.Mapper;
import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.internal.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
@@ -777,7 +777,7 @@ public class InternalUtils
*/
public static AnnotationProvider toAnnotationProvider(final Class element)
{
- return BeanModelUtils.toAnnotationProvider(element);
+ return InternalBeanModelUtils.toAnnotationProvider(element);
}
/**
@@ -1404,7 +1404,7 @@ public class InternalUtils
public static AnnotationProvider toAnnotationProvider(final Method element)
{
- return BeanModelUtils.toAnnotationProvider(element);
+ return InternalBeanModelUtils.toAnnotationProvider(element);
}
public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
new file mode 100644
index 0000000..a336365
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
@@ -0,0 +1,41 @@
+// Copyright 2008, 2009 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.ioc.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have a {@linkplain
+ * org.apache.tapestry5.ioc.MappedConfiguration mapped configuration}, to identify the type of key (often, a String),
+ * and type ofcontribution.
+ * <p/>
+ * Remember that when the key type is String, the map will be case-insensitive.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesMappedConfiguration
+{
+ /**
+ * The type of key used to identify contribution values.
+ */
+ Class key() default String.class;
+
+ /**
+ * The type of object which may be contributed into the service's configuration.
+ */
+ Class value();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
new file mode 100644
index 0000000..7c608f6
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
@@ -0,0 +1,33 @@
+// Copyright 2008, 2009 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.ioc.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have an {@linkplain
+ * org.apache.tapestry5.ioc.OrderedConfiguration ordered configuration}, to identify the type of contribution.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesOrderedConfiguration
+{
+ /**
+ * The type of object which may be contributed into the service's configuration.
+ */
+ Class value();
+}
[15/15] tapestry-5 git commit: Fifth pass creating the BeanModel and
Commons packages. Initial testing looks good.
Posted by th...@apache.org.
Fifth pass creating the BeanModel and Commons packages. Initial testing looks good.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/696bc7ae
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/696bc7ae
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/696bc7ae
Branch: refs/heads/beanmodel-split
Commit: 696bc7ae848f4b4f2421ff77ceb4858a2f10465c
Parents: eb7ec86
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 20:29:20 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 20:29:20 2014 -0200
----------------------------------------------------------------------
.../org/apache/tapestry5/PropertyConduit2.java | 2 +-
.../beaneditor/BeanModelSourceBuilder.java | 159 ++---
.../CoercingPropertyConduitWrapper.java | 8 +-
.../services/LiteralPropertyConduit.java | 2 +-
.../services/PropertyConduitSourceImpl.java | 46 +-
.../services/ClassPropertyAdapterImpl.java | 92 +--
.../services/AnnotationDataTypeAnalyzer.java | 32 +
.../ioc/internal/BasicDataTypeAnalyzers.java | 151 +++++
.../ioc/internal/util/InternalCommonsUtils.java | 608 +++++++++----------
.../internal/TapestryInternalUtils.java | 4 +-
.../internal/bindings/AbstractBinding.java | 2 +-
.../internal/bindings/PropBinding.java | 8 +-
.../services/AnnotationDataTypeAnalyzer.java | 32 -
.../InternalComponentResourcesImpl.java | 4 +-
.../tapestry5/modules/TapestryModule.java | 14 +-
.../app1/components/GenericTypeDisplay.java | 34 +-
.../integration/app1/pages/GenericTypeDemo.java | 24 +-
.../pages/GridWithSubmitWithContextDemo.java | 4 +-
.../integration/app2/base/ChildBasePage.java | 8 +-
.../integration/app2/base/ParentBasePage.java | 2 +-
.../pagelevel/OverrideMethodsTest.java | 14 +-
.../services/PropertyConduitSourceImplTest.java | 34 +-
.../org/apache/tapestry5/json/JSONArray.java | 2 +-
.../org/apache/tapestry5/json/JSONObject.java | 2 +-
24 files changed, 723 insertions(+), 565 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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
index 839d70f..1577a3d 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/PropertyConduit2.java
@@ -36,5 +36,5 @@ public interface PropertyConduit2 extends PropertyConduit
* @see java.lang.reflect.Field#getGenericType()
*
*/
- Type getPropertyGenericType();
+ Type getPropertyGenericType();
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
index 8cef66e..4ac3373 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
@@ -15,15 +15,22 @@ package org.apache.tapestry5.beaneditor;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
import javax.naming.OperationNotSupportedException;
+import javax.swing.JFrame;
import org.apache.tapestry5.internal.services.BeanModelSourceImpl;
import org.apache.tapestry5.internal.services.PropertyConduitSourceImpl;
import org.apache.tapestry5.internal.services.StringInterner;
import org.apache.tapestry5.internal.services.StringInternerImpl;
import org.apache.tapestry5.ioc.Configuration;
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
import org.apache.tapestry5.ioc.internal.services.PropertyAccessImpl;
@@ -31,6 +38,7 @@ import org.apache.tapestry5.ioc.internal.services.TypeCoercerImpl;
import org.apache.tapestry5.ioc.services.CoercionTuple;
import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
import org.apache.tapestry5.ioc.services.PropertyAccess;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.services.BeanModelSource;
import org.apache.tapestry5.services.DataTypeAnalyzer;
@@ -42,80 +50,89 @@ import org.slf4j.LoggerFactory;
* Tapestry-IoC. Usage of Tapestry-IoC is still recommended.
*/
public class BeanModelSourceBuilder {
-
- private TypeCoercer typeCoercer;
- private PropertyAccess propertyAccess;
- private PropertyConduitSource propertyConduitSource;
- private PlasticProxyFactory plasticProxyFactory;
- private DataTypeAnalyzer dataTypeAnalyzer;
- private ObjectLocator objectLocator;
- private StringInterner stringInterner;
- /**
- * Sets the {@link TypeCoercer} to be used.
- */
- public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer) {
- this.typeCoercer = typeCoercer;
-// propertyAccess = new PropertyAcc
- return this;
- }
+ private TypeCoercer typeCoercer;
+ private PropertyAccess propertyAccess;
+ private PropertyConduitSource propertyConduitSource;
+ private PlasticProxyFactory plasticProxyFactory;
+ private DataTypeAnalyzer dataTypeAnalyzer;
+ private ObjectLocator objectLocator;
+ private StringInterner stringInterner;
- public BeanModelSource build()
- {
-
- if (typeCoercer == null)
- {
- createTypeCoercer();
- }
-
- if (propertyAccess == null)
- {
- propertyAccess = new PropertyAccessImpl();
- }
-
- if (stringInterner == null)
- {
- stringInterner = new StringInternerImpl();
- }
-
- if (plasticProxyFactory == null)
- {
- plasticProxyFactory = new PlasticProxyFactoryImpl(getClass().getClassLoader(), LoggerFactory.getLogger(PlasticProxyFactory.class));
- }
-
- if (propertyConduitSource == null)
- {
- propertyConduitSource = new PropertyConduitSourceImpl(propertyAccess, plasticProxyFactory, typeCoercer, stringInterner);
- }
-
- return new BeanModelSourceImpl(typeCoercer, propertyAccess, propertyConduitSource, plasticProxyFactory, dataTypeAnalyzer, objectLocator);
-
- }
+ /**
+ * Sets the {@link TypeCoercer} to be used.
+ */
+ public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer)
+ {
+ this.typeCoercer = typeCoercer;
+ return this;
+ }
- private void createTypeCoercer() {
- CoercionTupleConfiguration configuration = new CoercionTupleConfiguration();
- BasicTypeCoercions.provideBasicTypeCoercions(configuration);
- typeCoercer = new TypeCoercerImpl(configuration.getTuples());
- }
-
- final private static class CoercionTupleConfiguration implements Configuration<CoercionTuple> {
-
- final private Collection<CoercionTuple> tuples = new ArrayList<CoercionTuple>();
+ public BeanModelSource build()
+ {
+
+ if (typeCoercer == null)
+ {
+ createTypeCoercer();
+ }
+
+ if (propertyAccess == null)
+ {
+ propertyAccess = new PropertyAccessImpl();
+ }
+
+ if (dataTypeAnalyzer == null)
+ {
+ dataTypeAnalyzer = BasicDataTypeAnalyzers.createDefaultDataTypeAnalyzer();
+ }
+
+ if (stringInterner == null)
+ {
+ stringInterner = new StringInternerImpl();
+ }
+
+ if (plasticProxyFactory == null)
+ {
+ plasticProxyFactory = new PlasticProxyFactoryImpl(getClass().getClassLoader(), LoggerFactory.getLogger(PlasticProxyFactory.class));
+ }
+
+ if (propertyConduitSource == null)
+ {
+ propertyConduitSource = new PropertyConduitSourceImpl(propertyAccess, plasticProxyFactory, typeCoercer, stringInterner);
+ }
+
+ return new BeanModelSourceImpl(typeCoercer, propertyAccess, propertyConduitSource, plasticProxyFactory, dataTypeAnalyzer, objectLocator);
+
+ }
+ private void createTypeCoercer()
+ {
+ CoercionTupleConfiguration configuration = new CoercionTupleConfiguration();
+ BasicTypeCoercions.provideBasicTypeCoercions(configuration);
+ typeCoercer = new TypeCoercerImpl(configuration.getTuples());
+ }
- @Override
- public void add(CoercionTuple tuble) {
- tuples.add(tuble);
- }
+ final private static class CoercionTupleConfiguration implements Configuration<CoercionTuple>
+ {
+
+ final private Collection<CoercionTuple> tuples = new ArrayList<CoercionTuple>();
+
+ @Override
+ public void add(CoercionTuple tuble)
+ {
+ tuples.add(tuble);
+ }
+
+ @Override
+ public void addInstance(Class<? extends CoercionTuple> clazz)
+ {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Collection<CoercionTuple> getTuples()
+ {
+ return tuples;
+ }
+
+ }
- @Override
- public void addInstance(Class<? extends CoercionTuple> clazz) {
- throw new RuntimeException("Not implemented");
- }
-
- public Collection<CoercionTuple> getTuples() {
- return tuples;
- }
-
- }
-
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/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
index 4dbfb2d..2127696 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
@@ -50,10 +50,10 @@ public class CoercingPropertyConduitWrapper implements PropertyConduit2
public Type getPropertyGenericType()
{
- if (conduit instanceof PropertyConduit2) {
- return ((PropertyConduit2) conduit).getPropertyGenericType();
- }
- return conduit.getPropertyType();
+ if (conduit instanceof PropertyConduit2) {
+ return ((PropertyConduit2) conduit).getPropertyGenericType();
+ }
+ return conduit.getPropertyType();
}
@SuppressWarnings("unchecked")
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
index 1fffd4f..e8cd58f 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/LiteralPropertyConduit.java
@@ -63,7 +63,7 @@ public class LiteralPropertyConduit extends PropertyConduitDelegate implements I
public Type getPropertyGenericType()
{
- return propertyType;
+ return propertyType;
}
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 09d234c..9148b46 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -524,28 +524,28 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
private Type getGenericType(PropertyAdapter adapter)
{
- Type genericType = null;
- if (adapter.getField() != null)
- {
- genericType = adapter.getField().getGenericType();
- }
- else if (adapter.getReadMethod() != null)
- {
- genericType = adapter.getReadMethod().getGenericReturnType();
- }
- else if (adapter.getWriteMethod() != null)
- {
- genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
- }
- else
- {
- throw new RuntimeException("Could not find accessor for property " + adapter.getName());
- }
-
- return genericType == null ? adapter.getType() : genericType;
- }
-
- private void implementSetter(PropertyAdapter adapter)
+ Type genericType = null;
+ if (adapter.getField() != null)
+ {
+ genericType = adapter.getField().getGenericType();
+ }
+ else if (adapter.getReadMethod() != null)
+ {
+ genericType = adapter.getReadMethod().getGenericReturnType();
+ }
+ else if (adapter.getWriteMethod() != null)
+ {
+ genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
+ }
+ else
+ {
+ throw new RuntimeException("Could not find accessor for property " + adapter.getName());
+ }
+
+ return genericType == null ? adapter.getType() : genericType;
+ }
+
+ private void implementSetter(PropertyAdapter adapter)
{
if (adapter.getWriteMethod() != null)
{
@@ -1488,7 +1488,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
public Type getPropertyGenericType()
{
- return rootClass;
+ return rootClass;
}
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
index 5d6dfec..9c5f36c4 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
@@ -57,11 +57,11 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
// TAP5-1493
if (readMethod != null && readMethod.isBridge())
{
- if (nonBridgeMethods == null)
- {
- nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
- }
- readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods);
+ if (nonBridgeMethods == null)
+ {
+ nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+ }
+ readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods);
}
// TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed
@@ -86,11 +86,11 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
if (writeMethod != null && writeMethod.isBridge())
{
- if (nonBridgeMethods == null)
- {
- nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
- }
- writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
+ if (nonBridgeMethods == null)
+ {
+ nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+ }
+ writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
}
// TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed
@@ -149,24 +149,24 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
* (default to providedmethod if none found)
*/
private Method findMethodWithSameNameAndParamCount(Method method, Map<String, List<Method>> groupedMethods) {
- List<Method> methodGroup = groupedMethods.get(method.getName());
- if (methodGroup != null)
- {
- for (Method nonBridgeMethod : methodGroup)
- {
- if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length)
- {
- // return the non-bridge method with the same name / argument count
- return nonBridgeMethod;
- }
- }
- }
-
- // default to the provided method
- return method;
- }
-
- /**
+ List<Method> methodGroup = groupedMethods.get(method.getName());
+ if (methodGroup != null)
+ {
+ for (Method nonBridgeMethod : methodGroup)
+ {
+ if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length)
+ {
+ // return the non-bridge method with the same name / argument count
+ return nonBridgeMethod;
+ }
+ }
+ }
+
+ // default to the provided method
+ return method;
+ }
+
+ /**
* Find all of the public methods that are not bridge methods and
* group them by method name
*
@@ -176,24 +176,24 @@ public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
*/
private Map<String, List<Method>> groupNonBridgeMethodsByName(Class type)
{
- Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap();
- for (Method method : type.getMethods())
- {
- if (!method.isBridge())
- {
- List<Method> methodGroup = methodGroupsByName.get(method.getName());
- if (methodGroup == null)
- {
- methodGroup = CollectionFactory.newList();
- methodGroupsByName.put(method.getName(), methodGroup);
- }
- methodGroup.add(method);
- }
- }
- return methodGroupsByName;
- }
-
- @Override
+ Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap();
+ for (Method method : type.getMethods())
+ {
+ if (!method.isBridge())
+ {
+ List<Method> methodGroup = methodGroupsByName.get(method.getName());
+ if (methodGroup == null)
+ {
+ methodGroup = CollectionFactory.newList();
+ methodGroupsByName.put(method.getName(), methodGroup);
+ }
+ methodGroup.add(method);
+ }
+ }
+ return methodGroupsByName;
+ }
+
+ @Override
public Class getBeanType()
{
return beanType;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java b/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
new file mode 100644
index 0000000..8b20666
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
@@ -0,0 +1,32 @@
+// 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 org.apache.tapestry5.beaneditor.DataType;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+
+/**
+ * Checks for the {@link DataType} annotation, returning its value if present.
+ */
+public class AnnotationDataTypeAnalyzer implements DataTypeAnalyzer
+{
+ public String identifyDataType(PropertyAdapter adapter)
+ {
+ DataType annotation = adapter.getAnnotation(DataType.class);
+
+ return annotation == null ? null : annotation.value();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
new file mode 100644
index 0000000..df7564f
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicDataTypeAnalyzers.java
@@ -0,0 +1,151 @@
+// Copyright 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.ioc.internal;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tapestry5.beaneditor.DataTypeConstants;
+import org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer;
+import org.apache.tapestry5.ioc.MappedConfiguration;
+import org.apache.tapestry5.ioc.OrderedConfiguration;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+
+/**
+ * Class that provides Tapestry's basic default data type analyzers.
+ */
+public class BasicDataTypeAnalyzers
+{
+
+ public static void contributeDataTypeAnalyzer(
+ OrderedConfiguration<DataTypeAnalyzer> configuration,
+ DataTypeAnalyzer defaultDataTypeAnalyzer) {
+ configuration.add("Annotation", new AnnotationDataTypeAnalyzer());
+ if (defaultDataTypeAnalyzer == null)
+ {
+ defaultDataTypeAnalyzer = createDefaultDataTypeAnalyzer();
+ }
+ configuration.add("Default", defaultDataTypeAnalyzer, "after:*");
+ }
+
+ public static DataTypeAnalyzer createDefaultDataTypeAnalyzer()
+ {
+ DefaultDataTypeAnalyzerMappedConfiguration mappedConfiguration = new DefaultDataTypeAnalyzerMappedConfiguration();
+ provideDefaultDataTypeAnalyzers(mappedConfiguration);
+ return new CombinedDataTypeAnalyzer(new AnnotationDataTypeAnalyzer(), new MapDataTypeAnalyzer(mappedConfiguration.getMap()));
+ }
+
+ /**
+ * Maps property types to data type names:
+ * <ul>
+ * <li>String --> text
+ * <li>Number --> number
+ * <li>Enum --> enum
+ * <li>Boolean --> boolean
+ * <li>Date --> date
+ * </ul>
+ */
+ public static void provideDefaultDataTypeAnalyzers(MappedConfiguration<Class, String> configuration)
+ {
+ // This is a special case contributed to avoid exceptions when a
+ // property type can't be
+ // matched. DefaultDataTypeAnalyzer converts the empty string to null.
+
+ configuration.add(Object.class, "");
+
+ configuration.add(String.class, DataTypeConstants.TEXT);
+ configuration.add(Number.class, DataTypeConstants.NUMBER);
+ configuration.add(Enum.class, DataTypeConstants.ENUM);
+ configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
+ configuration.add(Date.class, DataTypeConstants.DATE);
+ configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
+ }
+
+ final private static class DefaultDataTypeAnalyzerMappedConfiguration implements MappedConfiguration<Class, String>
+ {
+
+ final Map<Class, String> map = new HashMap<Class, String>();
+
+ @Override
+ public void add(Class key, String value) {
+ map.put(key, value);
+ }
+
+ @Override
+ public void override(Class key, String value) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public void addInstance(Class key, Class<? extends String> clazz) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
+ public void overrideInstance(Class key, Class<? extends String> clazz) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Map<Class, String> getMap() {
+ return map;
+ }
+
+ }
+
+ final private static class MapDataTypeAnalyzer implements DataTypeAnalyzer
+ {
+
+ final Map<Class, String> map;
+
+ public MapDataTypeAnalyzer(Map<Class, String> map) {
+ this.map = map;
+ }
+
+ @Override
+ public String identifyDataType(PropertyAdapter adapter) {
+ return map.get(adapter.getType());
+ }
+
+ }
+
+ final private static class CombinedDataTypeAnalyzer implements DataTypeAnalyzer
+ {
+
+ final private DataTypeAnalyzer first, second;
+
+ public CombinedDataTypeAnalyzer(DataTypeAnalyzer first, DataTypeAnalyzer second)
+ {
+ super();
+ this.first = first;
+ this.second = second;
+ }
+
+ @Override
+ public String identifyDataType(PropertyAdapter adapter)
+ {
+ String type = first.identifyDataType(adapter);
+ if (type == null)
+ {
+ type = second.identifyDataType(adapter);
+ }
+ return type;
+ }
+
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
index 3c391e0..2bc33d8 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -33,11 +33,11 @@ import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
*/
public class InternalCommonsUtils {
- /**
- * @since 5.3
- */
- public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
- private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+ /**
+ * @since 5.3
+ */
+ public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+ private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
/**
* Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
@@ -67,322 +67,322 @@ public class InternalCommonsUtils {
list.add(value);
}
- /**
- * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
- * convertable to a location.
- */
-
- public static Location locationOf(Object location)
- {
- if (location == null)
- return null;
-
- if (location instanceof Location)
- return (Location) location;
-
- if (location instanceof Locatable)
- return ((Locatable) location).getLocation();
-
- return null;
- }
+ /**
+ * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+ * convertable to a location.
+ */
+
+ public static Location locationOf(Object location)
+ {
+ if (location == null)
+ return null;
+
+ if (location instanceof Location)
+ return (Location) location;
+
+ if (location instanceof Locatable)
+ return ((Locatable) location).getLocation();
+
+ return null;
+ }
- public static AnnotationProvider toAnnotationProvider(final Method element)
- {
- if (element == null)
- return NULL_ANNOTATION_PROVIDER;
-
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return element.getAnnotation(annotationClass);
- }
- };
- }
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
- /**
- * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
- * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
- * underscore).
- *
- * @param expression a property expression
- * @return the expression with punctuation removed
- */
- public static String extractIdFromPropertyExpression(String expression)
- {
- return replace(expression, NON_WORD_PATTERN, "");
- }
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
- public static String replace(String input, Pattern pattern, String replacement)
- {
- return pattern.matcher(input).replaceAll(replacement);
- }
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
- /**
- * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
- * user presentable form.
- */
- public static String defaultLabel(String id, Messages messages, String propertyExpression)
- {
- String key = id + "-label";
-
- if (messages.contains(key))
- return messages.get(key);
-
- return toUserPresentable(extractIdFromPropertyExpression(InternalCommonsUtils.lastTerm(propertyExpression)));
- }
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalCommonsUtils.lastTerm(propertyExpression)));
+ }
- /**
- * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
- * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
- * following word), thus "user_id" also becomes "User Id".
- */
- public static String toUserPresentable(String id)
- {
- StringBuilder builder = new StringBuilder(id.length() * 2);
-
- char[] chars = id.toCharArray();
- boolean postSpace = true;
- boolean upcaseNext = true;
-
- for (char ch : chars)
- {
- if (upcaseNext)
- {
- builder.append(Character.toUpperCase(ch));
- upcaseNext = false;
-
- continue;
- }
-
- if (ch == '_')
- {
- builder.append(' ');
- upcaseNext = true;
- continue;
- }
-
- boolean upperCase = Character.isUpperCase(ch);
-
- if (upperCase && !postSpace)
- builder.append(' ');
-
- builder.append(ch);
-
- postSpace = upperCase;
- }
-
- return builder.toString();
- }
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
- /**
- * @since 5.3
- */
- public static AnnotationProvider toAnnotationProvider(final Class element)
- {
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationClass.cast(element.getAnnotation(annotationClass));
- }
- };
- }
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
- /**
- * Pattern used to eliminate leading and trailing underscores and dollar signs.
- */
- static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
- Pattern.CASE_INSENSITIVE);
+ /**
+ * Pattern used to eliminate leading and trailing underscores and dollar signs.
+ */
+ static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+ Pattern.CASE_INSENSITIVE);
- /**
- * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
- * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
- *
- * @param method
- * @return short string representation
- */
- public static String asString(Method method)
- {
- StringBuilder buffer = new StringBuilder();
-
- buffer.append(method.getDeclaringClass().getName());
- buffer.append(".");
- buffer.append(method.getName());
- buffer.append("(");
-
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- if (i > 0)
- buffer.append(", ");
-
- String name = method.getParameterTypes()[i].getSimpleName();
-
- buffer.append(name);
- }
-
- return buffer.append(")").toString();
- }
+ /**
+ * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+ * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+ *
+ * @param method
+ * @return short string representation
+ */
+ public static String asString(Method method)
+ {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append(method.getDeclaringClass().getName());
+ buffer.append(".");
+ buffer.append(method.getName());
+ buffer.append("(");
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ if (i > 0)
+ buffer.append(", ");
+
+ String name = method.getParameterTypes()[i].getSimpleName();
+
+ buffer.append(name);
+ }
+
+ return buffer.append(")").toString();
+ }
- /**
- * Strips leading "_" and "$" and trailing "_" from the name.
- */
- public static String stripMemberName(String memberName)
- {
- assert InternalCommonsUtils.isNonBlank(memberName);
- Matcher matcher = NAME_PATTERN.matcher(memberName);
-
- if (!matcher.matches())
- throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
- return matcher.group(1);
- }
+ /**
+ * Strips leading "_" and "$" and trailing "_" from the name.
+ */
+ public static String stripMemberName(String memberName)
+ {
+ assert InternalCommonsUtils.isNonBlank(memberName);
+ Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+ if (!matcher.matches())
+ throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+ return matcher.group(1);
+ }
- /**
- * Joins together some number of elements to form a comma separated list.
- */
- public static String join(List elements)
- {
- return InternalCommonsUtils.join(elements, ", ");
- }
+ /**
+ * Joins together some number of elements to form a comma separated list.
+ */
+ public static String join(List elements)
+ {
+ return InternalCommonsUtils.join(elements, ", ");
+ }
- /**
- * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
- * string "(blank)".
- *
- * @param elements
- * objects to be joined together
- * @param separator
- * used between elements when joining
- */
- public static String join(List elements, String separator)
- {
- switch (elements.size())
- {
- case 0:
- return "";
-
- case 1:
- return elements.get(0).toString();
-
- default:
-
- StringBuilder buffer = new StringBuilder();
- boolean first = true;
-
- for (Object o : elements)
- {
- if (!first)
- buffer.append(separator);
-
- String string = String.valueOf(o);
-
- if (string.equals(""))
- string = "(blank)";
-
- buffer.append(string);
-
- first = false;
- }
-
- return buffer.toString();
- }
- }
+ /**
+ * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+ * string "(blank)".
+ *
+ * @param elements
+ * objects to be joined together
+ * @param separator
+ * used between elements when joining
+ */
+ public static String join(List elements, String separator)
+ {
+ switch (elements.size())
+ {
+ case 0:
+ return "";
+
+ case 1:
+ return elements.get(0).toString();
+
+ default:
+
+ StringBuilder buffer = new StringBuilder();
+ boolean first = true;
+
+ for (Object o : elements)
+ {
+ if (!first)
+ buffer.append(separator);
+
+ String string = String.valueOf(o);
+
+ if (string.equals(""))
+ string = "(blank)";
+
+ buffer.append(string);
+
+ first = false;
+ }
+
+ return buffer.toString();
+ }
+ }
- /**
- * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
- *
- * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
- * empty
- */
- public static String joinSorted(Collection elements)
- {
- if (elements == null || elements.isEmpty())
- return "(none)";
-
- List<String> list = CollectionFactory.newList();
-
- for (Object o : elements)
- list.add(String.valueOf(o));
-
- Collections.sort(list);
-
- return join(list);
- }
+ /**
+ * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+ *
+ * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+ * empty
+ */
+ public static String joinSorted(Collection elements)
+ {
+ if (elements == null || elements.isEmpty())
+ return "(none)";
+
+ List<String> list = CollectionFactory.newList();
+
+ for (Object o : elements)
+ list.add(String.valueOf(o));
+
+ Collections.sort(list);
+
+ return join(list);
+ }
- /**
- * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
- */
-
- public static boolean isBlank(String input)
- {
- return input == null || input.length() == 0 || input.trim().length() == 0;
- }
+ /**
+ * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ */
+
+ public static boolean isBlank(String input)
+ {
+ return input == null || input.length() == 0 || input.trim().length() == 0;
+ }
- /**
- * Capitalizes a string, converting the first character to uppercase.
- */
- public static String capitalize(String input)
- {
- if (input.length() == 0)
- return input;
-
- return input.substring(0, 1).toUpperCase() + input.substring(1);
- }
+ /**
+ * Capitalizes a string, converting the first character to uppercase.
+ */
+ public static String capitalize(String input)
+ {
+ if (input.length() == 0)
+ return input;
+
+ return input.substring(0, 1).toUpperCase() + input.substring(1);
+ }
- public static boolean isNonBlank(String input)
- {
- return !isBlank(input);
- }
+ public static boolean isNonBlank(String input)
+ {
+ return !isBlank(input);
+ }
- /**
- * Return true if the input string contains the marker for symbols that must be expanded.
- */
- public static boolean containsSymbols(String input)
- {
- return input.contains("${");
- }
+ /**
+ * Return true if the input string contains the marker for symbols that must be expanded.
+ */
+ public static boolean containsSymbols(String input)
+ {
+ return input.contains("${");
+ }
- /**
- * Searches the string for the final period ('.') character and returns everything after that. The input string is
- * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
- * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
- * character.
- */
- public static String lastTerm(String input)
- {
- assert isNonBlank(input);
- int dotx = input.lastIndexOf('.');
-
- if (dotx < 0)
- return input;
-
- return input.substring(dotx + 1);
- }
+ /**
+ * Searches the string for the final period ('.') character and returns everything after that. The input string is
+ * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+ * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+ * character.
+ */
+ public static String lastTerm(String input)
+ {
+ assert isNonBlank(input);
+ int dotx = input.lastIndexOf('.');
+
+ if (dotx < 0)
+ return input;
+
+ return input.substring(dotx + 1);
+ }
- /**
- * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
- *
- * @param map
- * the map to extract keys from (may be null)
- * @return the sorted keys, or the empty set if map is null
- */
-
- public static List<String> sortedKeys(Map map)
- {
- if (map == null)
- return Collections.emptyList();
-
- List<String> keys = CollectionFactory.newList();
-
- for (Object o : map.keySet())
- keys.add(String.valueOf(o));
-
- Collections.sort(keys);
-
- return keys;
- }
+ /**
+ * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+ *
+ * @param map
+ * the map to extract keys from (may be null)
+ * @return the sorted keys, or the empty set if map is null
+ */
+
+ public static List<String> sortedKeys(Map map)
+ {
+ if (map == null)
+ return Collections.emptyList();
+
+ List<String> keys = CollectionFactory.newList();
+
+ for (Object o : map.keySet())
+ keys.add(String.valueOf(o));
+
+ Collections.sort(keys);
+
+ return keys;
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e032975..5e4ab42 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -457,9 +457,9 @@ public class TapestryInternalUtils
{
if (conduit instanceof PropertyConduit2)
{
- return ((PropertyConduit2) conduit).getPropertyGenericType();
+ return ((PropertyConduit2) conduit).getPropertyGenericType();
}
- return conduit.getPropertyType();
+ return conduit.getPropertyType();
}
public Object get(Object instance)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
index 8e731b7..572d61a 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/AbstractBinding.java
@@ -71,7 +71,7 @@ public abstract class AbstractBinding extends BaseLocatable implements Binding2
*/
public Type getBindingGenericType()
{
- return getBindingType();
+ return getBindingType();
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
index afe63eb..da4c53e 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/bindings/PropBinding.java
@@ -111,10 +111,10 @@ public class PropBinding extends AbstractBinding implements InternalPropBinding
@Override
public Type getBindingGenericType()
{
- if (conduit instanceof PropertyConduit2) {
- return ((PropertyConduit2) conduit).getPropertyGenericType();
- }
- return conduit.getPropertyType();
+ if (conduit instanceof PropertyConduit2) {
+ return ((PropertyConduit2) conduit).getPropertyGenericType();
+ }
+ return conduit.getPropertyType();
}
@Override
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
deleted file mode 100644
index 8b20666..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AnnotationDataTypeAnalyzer.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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 org.apache.tapestry5.beaneditor.DataType;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.apache.tapestry5.services.DataTypeAnalyzer;
-
-/**
- * Checks for the {@link DataType} annotation, returning its value if present.
- */
-public class AnnotationDataTypeAnalyzer implements DataTypeAnalyzer
-{
- public String identifyDataType(PropertyAdapter adapter)
- {
- DataType annotation = adapter.getAnnotation(DataType.class);
-
- return annotation == null ? null : annotation.value();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
index c51c086..5d0ac16 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
@@ -351,9 +351,9 @@ public class InternalComponentResourcesImpl extends LockSupport implements Inter
Binding binding = getBinding(parameterName);
Type genericType;
if (binding instanceof Binding2) {
- genericType = ((Binding2) binding).getBindingGenericType();
+ genericType = ((Binding2) binding).getBindingGenericType();
} else {
- genericType = binding.getBindingType();
+ genericType = binding.getBindingType();
}
return genericType;
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index e3902de..8a72a4d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -59,6 +59,7 @@ import org.apache.tapestry5.internal.util.StringRenderable;
import org.apache.tapestry5.internal.validator.ValidatorMacroImpl;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.services.*;
import org.apache.tapestry5.ioc.util.AvailableValues;
@@ -621,18 +622,7 @@ public final class TapestryModule
*/
public static void contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class, String> configuration)
{
- // This is a special case contributed to avoid exceptions when a
- // property type can't be
- // matched. DefaultDataTypeAnalyzer converts the empty string to null.
-
- configuration.add(Object.class, "");
-
- configuration.add(String.class, DataTypeConstants.TEXT);
- configuration.add(Number.class, DataTypeConstants.NUMBER);
- configuration.add(Enum.class, DataTypeConstants.ENUM);
- configuration.add(Boolean.class, DataTypeConstants.BOOLEAN);
- configuration.add(Date.class, DataTypeConstants.DATE);
- configuration.add(Calendar.class, DataTypeConstants.CALENDAR);
+ BasicDataTypeAnalyzers.provideDefaultDataTypeAnalyzers(configuration);
}
@Contribute(BeanBlockSource.class)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
index f6d2aa7..0a9365e 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/GenericTypeDisplay.java
@@ -25,21 +25,21 @@ import org.apache.tapestry5.ioc.annotations.Inject;
* Outputs the type and genericType of the 'value' binding in a div
*/
public class GenericTypeDisplay {
- @Inject
- private ComponentResources resources;
-
- @Parameter(required=true, defaultPrefix=BindingConstants.LITERAL)
- private String description;
-
- @Parameter(required=true)
- private Object value;
-
- void afterRender(MarkupWriter writer) {
- writer.element("div");
- Class<?> type = resources.getBoundType("value");
- Type genericType = resources.getBoundGenericType("value");
- String text = String.format("description=%s,type=%s,genericType=%s", description, type.getName(), genericType.toString());
- writer.write(text);
- writer.end();
- }
+ @Inject
+ private ComponentResources resources;
+
+ @Parameter(required=true, defaultPrefix=BindingConstants.LITERAL)
+ private String description;
+
+ @Parameter(required=true)
+ private Object value;
+
+ void afterRender(MarkupWriter writer) {
+ writer.element("div");
+ Class<?> type = resources.getBoundType("value");
+ Type genericType = resources.getBoundGenericType("value");
+ String text = String.format("description=%s,type=%s,genericType=%s", description, type.getName(), genericType.toString());
+ writer.write(text);
+ writer.end();
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
index 8e9fdd3..4fdc57a 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GenericTypeDemo.java
@@ -8,16 +8,16 @@ import java.util.Set;
import org.apache.tapestry5.annotations.Property;
public class GenericTypeDemo {
- private Set<Long> setOfLongs;
-
- @Property
- private Map<String, String> mapOfStrings;
-
- public List<List<Date>> getListOfListOfDates() {
- throw new UnsupportedOperationException();
- }
-
- public void setSetOfLongs(Set<Long> setOfLongs) {
- throw new UnsupportedOperationException();
- }
+ private Set<Long> setOfLongs;
+
+ @Property
+ private Map<String, String> mapOfStrings;
+
+ public List<List<Date>> getListOfListOfDates() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setSetOfLongs(Set<Long> setOfLongs) {
+ throw new UnsupportedOperationException();
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
index 9d4a774..0aac48f 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/GridWithSubmitWithContextDemo.java
@@ -45,9 +45,9 @@ public class GridWithSubmitWithContextDemo
{
return F.flow(library.getTracks()).sort(new Comparator<Track>(){
- @Override
+ @Override
public int compare(Track arg0, Track arg1) {
- return arg0.getId().compareTo(arg1.getId());
+ return arg0.getId().compareTo(arg1.getId());
}
});
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
index 44e9aff..5a787e9 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ChildBasePage.java
@@ -1,8 +1,8 @@
package org.apache.tapestry5.integration.app2.base;
public abstract class ChildBasePage extends ParentBasePage {
- @Override
- public String getObject() {
- return "foobar";
- }
+ @Override
+ public String getObject() {
+ return "foobar";
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
index 4030128..6c18c43 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app2/base/ParentBasePage.java
@@ -1,5 +1,5 @@
package org.apache.tapestry5.integration.app2.base;
public abstract class ParentBasePage {
- public abstract Object getObject();
+ public abstract Object getObject();
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
index b612d1f..c8e7d48 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/OverrideMethodsTest.java
@@ -9,13 +9,13 @@ public class OverrideMethodsTest extends Assert {
/** TAP5-901 */
@Test
public void override_abstract_methods() {
- PageTester tester = new PageTester(TestConstants.APP2_PACKAGE, TestConstants.APP2_NAME);
- try {
- Document doc = tester.renderPage("OverrideAbstractMethods");
- assertEquals("6", doc.getElementById("length").getChildMarkup());
- } finally {
- tester.shutdown();
- }
+ PageTester tester = new PageTester(TestConstants.APP2_PACKAGE, TestConstants.APP2_NAME);
+ try {
+ Document doc = tester.renderPage("OverrideAbstractMethods");
+ assertEquals("6", doc.getElementById("length").getChildMarkup());
+ } finally {
+ tester.shutdown();
+ }
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
index af25c62..a861883 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
@@ -167,15 +167,15 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase
}
static class GenericBean {
- public List<Date> dates;
- public List<GenericBean> genericBeans;
-
- public List<Long> getLongs() {
- return Collections.emptyList();
- }
-
- public void setMap(Map<String, Integer> map) {
- }
+ public List<Date> dates;
+ public List<GenericBean> genericBeans;
+
+ public List<Long> getLongs() {
+ return Collections.emptyList();
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ }
}
@Test
@@ -884,15 +884,15 @@ public class PropertyConduitSourceImplTest extends InternalBaseTestCase
// example from Howard
try {
- assertConduitPropertyType(Foo.class, "bar", Bar.class);
+ assertConduitPropertyType(Foo.class, "bar", Bar.class);
} catch (AssertionError e) {
- List<Method> matches = CollectionFactory.newList();
- for (Method method : Foo.class.getMethods()) {
- if (method.getName().equals("getBar")) {
- matches.add(method);
- }
- }
- fail(String.format("%s (possible candidates %s)", e.getMessage(), matches));
+ List<Method> matches = CollectionFactory.newList();
+ for (Method method : Foo.class.getMethods()) {
+ if (method.getName().equals("getBar")) {
+ matches.add(method);
+ }
+ }
+ fail(String.format("%s (possible candidates %s)", e.getMessage(), matches));
}
assertConduitPropertyType(AbstractFoo.class, "bar", AbstractBar.class);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
index 76ea531..7cb7d55 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONArray.java
@@ -386,7 +386,7 @@ public final class JSONArray extends JSONCollection implements Iterable<Object>
*/
public JSONArray put(Object value)
{
- // now testValidity checks for null values.
+ // now testValidity checks for null values.
// assert value != null;
JSONObject.testValidity(value);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/696bc7ae/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
----------------------------------------------------------------------
diff --git a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
index 7c5ccb4..1392bb8 100644
--- a/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
+++ b/tapestry-json/src/main/java/org/apache/tapestry5/json/JSONObject.java
@@ -913,7 +913,7 @@ public final class JSONObject extends JSONCollection
*/
static void printValue(JSONPrintSession session, Object value)
{
-
+
if (value instanceof JSONObject)
{
((JSONObject) value).print(session);
[03/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
deleted file mode 100644
index 701420f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ /dev/null
@@ -1,1563 +0,0 @@
-// Copyright 2007-2013 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 org.antlr.runtime.ANTLRInputStream;
-import org.antlr.runtime.CommonTokenStream;
-import org.antlr.runtime.tree.Tree;
-import org.apache.tapestry5.PropertyConduit;
-import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.internal.InternalPropertyConduit;
-import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
-import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
-import org.apache.tapestry5.internal.util.IntegerRange;
-import org.apache.tapestry5.internal.util.MultiKey;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.annotations.PostInjection;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.*;
-import org.apache.tapestry5.services.ComponentClasses;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.InvalidationEventHub;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
-
-public class PropertyConduitSourceImpl implements PropertyConduitSource
-{
- static class ConduitMethods
- {
- private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
-
- private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
- Object.class);
-
- private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
- "getPropertyType");
-
- private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class,
- "getPropertyGenericType");
-
- private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
- "getPropertyName");
-
- private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
- "getAnnotation", Class.class);
-
- }
-
- static class DelegateMethods
- {
- static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
-
- static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
-
- static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class);
- }
-
- static class ArrayListMethods
- {
- static final Method ADD = getMethod(ArrayList.class, "add", Object.class);
- }
-
- static class HashMapMethods
- {
- static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class);
- }
-
- private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadNull().returnResult();
- }
- };
-
- private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
- {Object.class.getName()};
-
- @SuppressWarnings("unchecked")
- private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
- {
- try
- {
- return containingClass.getMethod(name, parameterTypes);
- } catch (NoSuchMethodException ex)
- {
- throw new IllegalArgumentException(ex);
- }
- }
-
- private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
- {
- return new MethodDescription(getMethod(containingClass, name, parameterTypes));
- }
-
- private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
-
- /**
- * How are null values in intermdiate terms to be handled?
- */
- private enum NullHandling
- {
- /**
- * Add code to check for null and throw exception if null.
- */
- FORBID,
-
- /**
- * Add code to check for null and short-circuit (i.e., the "?."
- * safe-dereference operator)
- */
- ALLOW
- }
-
- /**
- * One term in an expression. Expressions start with some root type and each term advances
- * to a new type.
- */
- private class Term
- {
- /**
- * The generic type of the term.
- */
- final Type type;
-
- final Class genericType;
-
- /**
- * Describes the term, for use in error messages.
- */
- final String description;
-
- final AnnotationProvider annotationProvider;
-
- /**
- * Callback that will implement the term.
- */
- final InstructionBuilderCallback callback;
-
- Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
- InstructionBuilderCallback callback)
- {
- this.type = type;
- this.genericType = genericType;
- this.description = description;
- this.annotationProvider = annotationProvider;
- this.callback = callback;
- }
-
- Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback)
- {
- this(type, GenericsUtils.asClass(type), description, annotationProvider, callback);
- }
-
- Term(Type type, String description, InstructionBuilderCallback callback)
- {
- this(type, description, null, callback);
- }
-
- /**
- * Returns a clone of this Term with a new callback.
- */
- Term withCallback(InstructionBuilderCallback newCallback)
- {
- return new Term(type, genericType, description, annotationProvider, newCallback);
- }
- }
-
- private final PropertyAccess access;
-
- private final PlasticProxyFactory proxyFactory;
-
- private final TypeCoercer typeCoercer;
-
- private final StringInterner interner;
-
- /**
- * Keyed on combination of root class and expression.
- */
- private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap();
-
- private final Invariant invariantAnnotation = new Invariant()
- {
- public Class<? extends Annotation> annotationType()
- {
- return Invariant.class;
- }
- };
-
- private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider()
- {
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- if (annotationClass == Invariant.class)
- return annotationClass.cast(invariantAnnotation);
-
- return null;
- }
- };
-
- private final PropertyConduit literalTrue;
-
- private final PropertyConduit literalFalse;
-
- private final PropertyConduit literalNull;
-
- private final PropertyConduitDelegate sharedDelegate;
-
- /**
- * Encapsulates the process of building a PropertyConduit instance from an
- * expression, as an {@link PlasticClassTransformer}.
- */
- class PropertyConduitBuilder implements PlasticClassTransformer
- {
- private final Class rootType;
-
- private final String expression;
-
- private final Tree tree;
-
- private Class conduitPropertyType;
-
- private Type conduitPropertyGenericType;
-
- private String conduitPropertyName;
-
- private AnnotationProvider annotationProvider = nullAnnotationProvider;
-
- private PlasticField delegateField;
-
- private PlasticClass plasticClass;
-
- private PlasticMethod getRootMethod, navMethod;
-
- PropertyConduitBuilder(Class rootType, String expression, Tree tree)
- {
- this.rootType = rootType;
- this.expression = expression;
- this.tree = tree;
- }
-
- public void transform(PlasticClass plasticClass)
- {
- this.plasticClass = plasticClass;
-
- // Create the various methods; also determine the conduit's property type, property name and identify
- // the annotation provider.
-
- implementNavMethodAndAccessors();
-
- implementOtherMethods();
-
- plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
- }
-
- private void implementOtherMethods()
- {
- PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class,
- "annotationProvider").inject(annotationProvider);
-
- plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField);
-
- plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadConstant(conduitPropertyName).returnResult();
- }
- });
-
- final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject(
- conduitPropertyType);
-
- plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadThis().getField(propertyTypeField).returnResult();
- }
- });
-
- final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject(
- conduitPropertyGenericType);
-
- plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadThis().getField(propertyGenericTypeField).returnResult();
- }
- });
- }
-
- /**
- * Creates a method that does a conversion from Object to the expected root type, with
- * a null check.
- */
- private void implementGetRoot()
- {
- getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
- SINGLE_OBJECT_ARGUMENT, null);
-
- getRootMethod.changeImplementation(new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.throwException(NullPointerException.class,
- String.format("Root object of property expression '%s' is null.", expression));
- }
- });
-
- builder.checkcast(rootType).returnResult();
- }
- });
- }
-
- private boolean isLeaf(Tree node)
- {
- int type = node.getType();
-
- return type != DEREF && type != SAFEDEREF;
- }
-
- private void implementNavMethodAndAccessors()
- {
- implementGetRoot();
-
- // First, create the navigate method.
-
- final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
-
- Type activeType = rootType;
-
- Tree node = tree;
-
- while (!isLeaf(node))
- {
- Term term = analyzeDerefNode(activeType, node);
-
- callbacks.add(term.callback);
-
- activeType = term.type;
-
- // Second term is the continuation, possibly another chained
- // DEREF, etc.
- node = node.getChild(1);
- }
-
- Class activeClass = GenericsUtils.asClass(activeType);
-
- if (callbacks.isEmpty())
- {
- navMethod = getRootMethod;
- } else
- {
- navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
- SINGLE_OBJECT_ARGUMENT, null);
-
- navMethod.changeImplementation(new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
-
- for (InstructionBuilderCallback callback : callbacks)
- {
- callback.doBuild(builder);
- }
-
- builder.returnResult();
- }
- });
- }
-
- implementAccessors(activeType, node);
- }
-
- private void implementAccessors(Type activeType, Tree node)
- {
- switch (node.getType())
- {
- case IDENTIFIER:
-
- implementPropertyAccessors(activeType, node);
-
- return;
-
- case INVOKE:
-
- // So, at this point, we have the navigation method written
- // and it covers all but the terminal
- // de-reference. node is an IDENTIFIER or INVOKE. We're
- // ready to use the navigation
- // method to implement get() and set().
-
- implementMethodAccessors(activeType, node);
-
- return;
-
- case RANGEOP:
-
- // As currently implemented, RANGEOP can only appear as the
- // top level, which
- // means we didn't need the navigate method after all.
-
- implementRangeOpGetter(node);
- implementNoOpSetter();
-
- conduitPropertyType = IntegerRange.class;
- conduitPropertyGenericType = IntegerRange.class;
-
- return;
-
- case LIST:
-
- implementListGetter(node);
- implementNoOpSetter();
-
- conduitPropertyType = List.class;
- conduitPropertyGenericType = List.class;
-
- return;
-
- case MAP:
- implementMapGetter(node);
- implementNoOpSetter();
-
- conduitPropertyType = Map.class;
- conduitPropertyGenericType = Map.class;
-
- return;
-
-
- case NOT:
- implementNotOpGetter(node);
- implementNoOpSetter();
-
- conduitPropertyType = boolean.class;
- conduitPropertyGenericType = boolean.class;
-
- return;
-
- default:
- throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
- }
- }
-
- public void implementMethodAccessors(final Type activeType, final Tree invokeNode)
- {
- final Term term = buildInvokeTerm(activeType, invokeNode);
-
- implementNoOpSetter();
-
- conduitPropertyName = term.description;
- conduitPropertyType = term.genericType;
- conduitPropertyGenericType = term.genericType;
- annotationProvider = term.annotationProvider;
-
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- term.callback.doBuild(builder);
-
- boxIfPrimitive(builder, conduitPropertyType);
-
- builder.returnResult();
- }
- });
-
- implementNoOpSetter();
- }
-
- public void implementPropertyAccessors(Type activeType, Tree identifierNode)
- {
- String propertyName = identifierNode.getText();
-
- PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
-
- conduitPropertyName = propertyName;
- conduitPropertyType = adapter.getType();
- conduitPropertyGenericType = getGenericType(adapter);
- annotationProvider = adapter;
-
- implementGetter(adapter);
- implementSetter(adapter);
- }
-
- private Type getGenericType(PropertyAdapter adapter)
- {
- Type genericType = null;
- if (adapter.getField() != null)
- {
- genericType = adapter.getField().getGenericType();
- }
- else if (adapter.getReadMethod() != null)
- {
- genericType = adapter.getReadMethod().getGenericReturnType();
- }
- else if (adapter.getWriteMethod() != null)
- {
- genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
- }
- else
- {
- throw new RuntimeException("Could not find accessor for property " + adapter.getName());
- }
-
- return genericType == null ? adapter.getType() : genericType;
- }
-
- private void implementSetter(PropertyAdapter adapter)
- {
- if (adapter.getWriteMethod() != null)
- {
- implementSetter(adapter.getWriteMethod());
- return;
- }
-
- if (adapter.getField() != null && adapter.isUpdate())
- {
- implementSetter(adapter.getField());
- return;
- }
-
- implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
- rootType.getName());
- }
-
- private boolean isStatic(Member member)
- {
- return Modifier.isStatic(member.getModifiers());
- }
-
- private void implementSetter(final Field field)
- {
- if (isStatic(field))
- {
- plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
-
- builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
- builder.returnResult();
- }
- });
-
- return;
- }
-
- plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
-
- builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
- builder.returnResult();
- }
- });
- }
-
- private void implementSetter(final Method writeMethod)
- {
- plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- Class propertyType = writeMethod.getParameterTypes()[0];
- String propertyTypeName = PlasticUtils.toTypeName(propertyType);
-
- builder.loadArgument(1).castOrUnbox(propertyTypeName);
-
- builder.invoke(writeMethod);
-
- builder.returnResult();
- }
- });
- }
-
- private void implementGetter(PropertyAdapter adapter)
- {
- if (adapter.getReadMethod() != null)
- {
- implementGetter(adapter.getReadMethod());
- return;
- }
-
- if (adapter.getField() != null)
- {
- implementGetter(adapter.getField());
- return;
- }
-
- implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression,
- rootType.getName());
- }
-
- private void implementGetter(final Field field)
- {
- if (isStatic(field))
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
- // Cast not necessary here since the return type of get() is Object
-
- boxIfPrimitive(builder, field.getType());
-
- builder.returnResult();
- }
- });
-
- return;
- }
-
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
- // Cast not necessary here since the return type of get() is Object
-
- boxIfPrimitive(builder, field.getType());
-
- builder.returnResult();
- }
- });
- }
-
- private void implementGetter(final Method readMethod)
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- invokeMethod(builder, readMethod, null, 0);
-
- boxIfPrimitive(builder, conduitPropertyType);
-
- builder.returnResult();
- }
- });
- }
-
- private void implementRangeOpGetter(final Tree rangeNode)
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- // Put the delegate on top of the stack
-
- builder.loadThis().getField(getDelegateField());
-
- invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0);
-
- builder.returnResult();
- }
- });
- }
-
- /**
- * @param node
- * subexpression to invert
- */
- private void implementNotOpGetter(final Tree node)
- {
- // Implement get() as navigate, then do a method invocation based on node
- // then, then pass (wrapped) result to delegate.invert()
-
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- Type expressionType = implementNotExpression(builder, node);
-
- // Yes, we know this will always be the case, for now.
-
- boxIfPrimitive(builder, expressionType);
-
- builder.returnResult();
- }
- });
- }
-
- /**
- * The first part of any implementation of get() or set(): invoke the navigation method
- * and if the result is null, return immediately.
- */
- private void invokeNavigateMethod(InstructionBuilder builder)
- {
- builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
-
- builder.dupe().when(Condition.NULL, RETURN_NULL);
- }
-
- /**
- * Uses the builder to add instructions for a subexpression.
- *
- * @param builder
- * used to add instructions
- * @param activeType
- * type of value on top of the stack when this code will execute, or null if no value on stack
- * @param node
- * defines the expression
- * @return the expression type
- */
- private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
- {
- Term term;
-
- while (true)
- {
- switch (node.getType())
- {
- case IDENTIFIER:
- case INVOKE:
-
- if (activeType == null)
- {
- invokeGetRootMethod(builder);
-
- activeType = rootType;
- }
-
- term = buildTerm(activeType, node);
-
- term.callback.doBuild(builder);
-
- return term.type;
-
- case INTEGER:
-
- builder.loadConstant(new Long(node.getText()));
-
- return long.class;
-
- case DECIMAL:
-
- builder.loadConstant(new Double(node.getText()));
-
- return double.class;
-
- case STRING:
-
- builder.loadConstant(node.getText());
-
- return String.class;
-
- case DEREF:
- case SAFEDEREF:
-
- if (activeType == null)
- {
- invokeGetRootMethod(builder);
-
- activeType = rootType;
- }
-
- term = analyzeDerefNode(activeType, node);
-
- term.callback.doBuild(builder);
-
- activeType = GenericsUtils.asClass(term.type);
-
- node = node.getChild(1);
-
- break;
-
- case TRUE:
- case FALSE:
-
- builder.loadConstant(node.getType() == TRUE ? 1 : 0);
-
- return boolean.class;
-
- case LIST:
-
- return implementListConstructor(builder, node);
-
- case MAP:
- return implementMapConstructor(builder, node);
-
- case NOT:
-
- return implementNotExpression(builder, node);
-
- case THIS:
-
- invokeGetRootMethod(builder);
-
- return rootType;
-
- case NULL:
-
- builder.loadNull();
-
- return Void.class;
-
- default:
- throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
- IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
- }
- }
- }
-
- public void invokeGetRootMethod(InstructionBuilder builder)
- {
- builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
- }
-
- private void implementListGetter(final Tree listNode)
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- implementListConstructor(builder, listNode);
-
- builder.returnResult();
- }
- });
- }
-
- private Type implementListConstructor(InstructionBuilder builder, Tree listNode)
- {
- // First, create an empty instance of ArrayList
-
- int count = listNode.getChildCount();
-
- builder.newInstance(ArrayList.class);
- builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class);
-
- for (int i = 0; i < count; i++)
- {
- builder.dupe(); // the ArrayList
-
- Type expressionType = implementSubexpression(builder, null, listNode.getChild(i));
-
- boxIfPrimitive(builder, GenericsUtils.asClass(expressionType));
-
- // Add the value to the array, then pop off the returned boolean
- builder.invoke(ArrayListMethods.ADD).pop();
- }
-
- return ArrayList.class;
- }
-
- private void implementMapGetter(final Tree mapNode)
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- implementMapConstructor(builder, mapNode);
-
- builder.returnResult();
- }
- });
- }
-
- private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode)
- {
- int count = mapNode.getChildCount();
- builder.newInstance(HashMap.class);
- builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
-
- for (int i = 0; i < count; i += 2)
- {
- builder.dupe();
-
- //build the key:
- Type keyType = implementSubexpression(builder, null, mapNode.getChild(i));
- boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
-
- //and the value:
- Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
- boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
-
- //put the value into the array, then pop off the returned object.
- builder.invoke(HashMapMethods.PUT).pop();
-
- }
-
- return HashMap.class;
- }
-
-
- private void implementNoOpSetter()
- {
- implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
- rootType.getName());
- }
-
- public void implementNoOpMethod(MethodDescription method, String format, Object... arguments)
- {
- final String message = String.format(format, arguments);
-
- plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.throwException(RuntimeException.class, message);
- }
- });
- }
-
- /**
- * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
- * to be evaluated, and potentially coerced, so that they may be passed to the method.
- *
- * @param builder
- * constructs code
- * @param method
- * method to invoke
- * @param node
- * INVOKE or RANGEOP node
- * @param childOffset
- * offset within the node to the first child expression (1 in an INVOKE node because the
- * first child is the method name, 0 in a RANGEOP node)
- */
- private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
- {
- // We start with the target object for the method on top of the stack.
- // Next, we have to push each method parameter, which may include boxing/deboxing
- // and coercion. Once the code is in good shape, there's a lot of room to optimize
- // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary
- // trips through TypeCoercer). We might also want to have a local variable to store
- // the root object (result of getRoot()).
-
- Class[] parameterTypes = method.getParameterTypes();
-
- for (int i = 0; i < parameterTypes.length; i++)
- {
- Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset));
-
- // The value left on the stack is not primitive, and expressionType represents
- // its real type.
-
- Class parameterType = parameterTypes[i];
-
- if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType)))
- {
- boxIfPrimitive(builder, expressionType);
-
- builder.loadThis().getField(getDelegateField());
- builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType));
- builder.invoke(DelegateMethods.COERCE);
-
- if (parameterType.isPrimitive())
- {
- builder.castOrUnbox(parameterType.getName());
- } else
- {
- builder.checkcast(parameterType);
- }
- }
-
- // And that should leave an object of the correct type on the stack,
- // ready for the method invocation.
- }
-
- // Now the target object and all parameters are in place.
-
- builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(),
- method.getParameterTypes());
- }
-
- /**
- * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
- * peform the dereference.
- *
- * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
- * to advance the evaluation of the expression form the previous value to the current
- */
- private Term analyzeDerefNode(Type activeType, Tree node)
- {
- // The first child is the term.
-
- Tree term = node.getChild(0);
-
- boolean allowNull = node.getType() == SAFEDEREF;
-
- return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
- }
-
- private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling)
- {
- assertNodeType(term, IDENTIFIER, INVOKE);
-
- final Term simpleTerm = buildTerm(activeType, term);
-
- if (simpleTerm.genericType.isPrimitive())
- return simpleTerm;
-
- return simpleTerm.withCallback(new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- simpleTerm.callback.doBuild(builder);
-
- builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- switch (nullHandling)
- {
- // It is necessary to load a null onto the stack (even if there's already one
- // there) because of the verifier. It sees the return when the stack contains an
- // intermediate value (along the navigation chain) and thinks the method is
- // returning a value of the wrong type.
-
- case ALLOW:
- builder.loadNull().returnResult();
-
- case FORBID:
-
- builder.loadConstant(simpleTerm.description);
- builder.loadConstant(expression);
- builder.loadArgument(0);
-
- builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class,
- "nullTerm", String.class, String.class, Object.class);
- builder.throwException();
-
- break;
-
- }
- }
- });
- }
- });
- }
-
- private void assertNodeType(Tree node, int... expected)
- {
- int type = node.getType();
-
- for (int e : expected)
- {
- if (type == e)
- return;
- }
-
- throw unexpectedNodeType(node, expected);
- }
-
- private RuntimeException unexpectedNodeType(Tree node, int... expected)
- {
- List<String> tokenNames = CollectionFactory.newList();
-
- for (int i = 0; i < expected.length; i++)
- tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]);
-
- String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
- node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
- InternalUtils.joinSorted(tokenNames));
-
- return new RuntimeException(message);
- }
-
- private Term buildTerm(Type activeType, Tree termNode)
- {
- switch (termNode.getType())
- {
- case INVOKE:
-
- return buildInvokeTerm(activeType, termNode);
-
- case IDENTIFIER:
-
- return buildPropertyAccessTerm(activeType, termNode);
-
- default:
- throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER);
- }
- }
-
- private Term buildPropertyAccessTerm(Type activeType, Tree termNode)
- {
- String propertyName = termNode.getText();
-
- PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
-
- // Prefer the accessor over the field
-
- if (adapter.getReadMethod() != null)
- {
- return buildGetterMethodAccessTerm(activeType, propertyName,
- adapter.getReadMethod());
- }
-
- if (adapter.getField() != null)
- {
- return buildPublicFieldAccessTerm(activeType, propertyName,
- adapter.getField());
- }
-
- throw new RuntimeException(String.format(
- "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
- adapter.getBeanType().getName()));
- }
-
- public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName)
- {
- Class activeClass = GenericsUtils.asClass(activeType);
-
- ClassPropertyAdapter classAdapter = access.getAdapter(activeClass);
- PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
-
- if (adapter == null)
- {
- final List<String> names = classAdapter.getPropertyNames();
- final String className = activeClass.getName();
- throw new UnknownValueException(String.format(
- "Class %s does not contain a property (or public field) named '%s'.", className, propertyName),
- new AvailableValues("Properties (and public fields)", names));
- }
- return adapter;
- }
-
- private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod)
- {
- Type returnType = GenericsUtils.extractActualType(activeType, readMethod);
-
- return new Term(returnType, propertyName, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeMethod(builder, readMethod, null, 0);
-
- Type genericType = GenericsUtils.extractActualType(activeType, readMethod);
-
- castToGenericType(builder, readMethod.getReturnType(), genericType);
- }
- });
- }
-
- private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field)
- {
- final Type fieldType = GenericsUtils.extractActualType(activeType, field);
-
- return new Term(fieldType, propertyName, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- Class rawFieldType = field.getType();
-
- String rawTypeName = PlasticUtils.toTypeName(rawFieldType);
- String containingClassName = field.getDeclaringClass().getName();
- String fieldName = field.getName();
-
- if (isStatic(field))
- {
- // We've gone to the trouble of loading the root object, or navigated to some other object,
- // but we don't need or want the instance, since it's a static field we're accessing.
- // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but
- // access to public fields is relatively rare, and the cost is just the unused bytecode.
-
- builder.pop();
-
- builder.getStaticField(containingClassName, fieldName, rawTypeName);
-
- } else
- {
- builder.getField(containingClassName, fieldName, rawTypeName);
- }
-
- castToGenericType(builder, rawFieldType, fieldType);
- }
-
- });
- }
-
- /**
- * Casts the results of a field read or method invocation based on generic information.
- *
- * @param builder
- * used to add instructions
- * @param rawType
- * the simple type (often Object) of the field (or method return type)
- * @param genericType
- * the generic Type, from which parameterizations can be determined
- */
- private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
- {
- if (!genericType.equals(rawType))
- {
- Class castType = GenericsUtils.asClass(genericType);
- builder.checkcast(castType);
- }
- }
-
- private Term buildInvokeTerm(final Type activeType, final Tree invokeNode)
- {
- String methodName = invokeNode.getChild(0).getText();
-
- int parameterCount = invokeNode.getChildCount() - 1;
-
- Class activeClass = GenericsUtils.asClass(activeType);
-
- final Method method = findMethod(activeClass, methodName, parameterCount);
-
- if (method.getReturnType().equals(void.class))
- throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(),
- methodName));
-
- Type returnType = GenericsUtils.extractActualType(activeType, method);
-
- return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeMethod(builder, method, invokeNode, 1);
-
- Type genericType = GenericsUtils.extractActualType(activeType, method);
-
- castToGenericType(builder, method.getReturnType(), genericType);
- }
- }
- );
- }
-
- private Method findMethod(Class activeType, String methodName, int parameterCount)
- {
- Class searchType = activeType;
-
- while (true)
- {
-
- for (Method method : searchType.getMethods())
- {
- if (method.getParameterTypes().length == parameterCount
- && method.getName().equalsIgnoreCase(methodName))
- return method;
- }
-
- // TAP5-330
- if (searchType != Object.class)
- {
- searchType = Object.class;
- } else
- {
- throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
- activeType.getName(), methodName));
- }
- }
- }
-
- public void boxIfPrimitive(InstructionBuilder builder, Type termType)
- {
- boxIfPrimitive(builder, GenericsUtils.asClass(termType));
- }
-
- public void boxIfPrimitive(InstructionBuilder builder, Class termType)
- {
- if (termType.isPrimitive())
- builder.boxPrimitive(termType.getName());
- }
-
- public Class implementNotExpression(InstructionBuilder builder, final Tree notNode)
- {
- Type expressionType = implementSubexpression(builder, null, notNode.getChild(0));
-
- boxIfPrimitive(builder, expressionType);
-
- // Now invoke the delegate invert() method
-
- builder.loadThis().getField(getDelegateField());
-
- builder.swap().invoke(DelegateMethods.INVERT);
-
- return boolean.class;
- }
-
- /**
- * Defer creation of the delegate field unless actually needed.
- */
- private PlasticField getDelegateField()
- {
- if (delegateField == null)
- delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject(
- sharedDelegate);
-
- return delegateField;
- }
- }
-
- public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
- PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
- {
- this.access = access;
- this.proxyFactory = proxyFactory;
- this.typeCoercer = typeCoercer;
- this.interner = interner;
-
- literalTrue = createLiteralConduit(Boolean.class, true);
- literalFalse = createLiteralConduit(Boolean.class, false);
- literalNull = createLiteralConduit(Void.class, null);
-
- sharedDelegate = new PropertyConduitDelegate(typeCoercer);
- }
-
- @PostInjection
- public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub)
- {
- hub.clearOnInvalidation(cache);
- }
-
-
- public PropertyConduit create(Class rootClass, String expression)
- {
- assert rootClass != null;
- assert InternalUtils.isNonBlank(expression);
-
- MultiKey key = new MultiKey(rootClass, expression);
-
- PropertyConduit result = cache.get(key);
-
- if (result == null)
- {
- result = build(rootClass, expression);
- cache.put(key, result);
- }
-
- return result;
- }
-
- /**
- * Builds a subclass of {@link PropertyConduitDelegate} that implements the
- * get() and set() methods and overrides the
- * constructor. In a worst-case race condition, we may build two (or more)
- * conduits for the same
- * rootClass/expression, and it will get sorted out when the conduit is
- * stored into the cache.
- *
- * @param rootClass
- * class of root object for expression evaluation
- * @param expression
- * expression to be evaluated
- * @return the conduit
- */
- private PropertyConduit build(final Class rootClass, String expression)
- {
- Tree tree = parse(expression);
-
- try
- {
- switch (tree.getType())
- {
- case TRUE:
-
- return literalTrue;
-
- case FALSE:
-
- return literalFalse;
-
- case NULL:
-
- return literalNull;
-
- case INTEGER:
-
- // Leading '+' may screw this up.
- // TODO: Singleton instance for "0", maybe "1"?
-
- return createLiteralConduit(Long.class, new Long(tree.getText()));
-
- case DECIMAL:
-
- // Leading '+' may screw this up.
- // TODO: Singleton instance for "0.0"?
-
- return createLiteralConduit(Double.class, new Double(tree.getText()));
-
- case STRING:
-
- return createLiteralConduit(String.class, tree.getText());
-
- case RANGEOP:
-
- Tree fromNode = tree.getChild(0);
- Tree toNode = tree.getChild(1);
-
- // If the range is defined as integers (not properties, etc.)
- // then it is possible to calculate the value here, once, and not
- // build a new class.
-
- if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER)
- break;
-
- int from = Integer.parseInt(fromNode.getText());
- int to = Integer.parseInt(toNode.getText());
-
- IntegerRange ir = new IntegerRange(from, to);
-
- return createLiteralConduit(IntegerRange.class, ir);
-
- case THIS:
-
- return createLiteralThisPropertyConduit(rootClass);
-
- default:
- break;
- }
-
- return proxyFactory.createProxy(InternalPropertyConduit.class,
- new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
- } catch (Exception ex)
- {
- throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
- expression, ExceptionUtils.toMessage(ex)), expression, ex);
- }
- }
-
- private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass)
- {
- return new PropertyConduit()
- {
- public Object get(Object instance)
- {
- return instance;
- }
-
- public void set(Object instance, Object value)
- {
- throw new RuntimeException("Literal values are not updateable.");
- }
-
- public Class getPropertyType()
- {
- return rootClass;
- }
-
- public Type getPropertyGenericType()
- {
- return rootClass;
- }
-
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return invariantAnnotationProvider.getAnnotation(annotationClass);
- }
- };
- }
-
- private <T> PropertyConduit createLiteralConduit(Class<T> type, T value)
- {
- return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format(
- "LiteralPropertyConduit[%s]", value), value);
- }
-
- private Tree parse(String expression)
- {
- InputStream is = new ByteArrayInputStream(expression.getBytes());
-
- ANTLRInputStream ais;
-
- try
- {
- ais = new ANTLRInputStream(is);
- } catch (IOException ex)
- {
- throw new RuntimeException(ex);
- }
-
- PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais);
-
- CommonTokenStream tokens = new CommonTokenStream(lexer);
-
- PropertyExpressionParser parser = new PropertyExpressionParser(tokens);
-
- try
- {
- return (Tree) parser.start().getTree();
- } catch (Exception ex)
- {
- throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
- ex.getMessage()), ex);
- }
- }
-
- /**
- * May be invoked from fabricated PropertyConduit instances.
- */
- @SuppressWarnings("unused")
- public static NullPointerException nullTerm(String term, String expression, Object root)
- {
- String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term,
- expression, root);
-
- return new NullPointerException(message);
- }
-
- private static String toUniqueId(Method method)
- {
- StringBuilder builder = new StringBuilder(method.getName()).append("(");
- String sep = "";
-
- for (Class parameterType : method.getParameterTypes())
- {
- builder.append(sep);
- builder.append(PlasticUtils.toTypeName(parameterType));
-
- sep = ",";
- }
-
- return builder.append(")").toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
deleted file mode 100644
index 7b2b7ab..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2006 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.util;
-
-import java.util.Iterator;
-
-/**
- * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the
- * finish value).
- */
-public final class IntegerRange implements Iterable<Integer>
-{
- private final int start;
-
- private final int finish;
-
- private class RangeIterator implements Iterator<Integer>
- {
- private final int increment;
-
- private int value = start;
-
- private boolean hasNext = true;
-
- RangeIterator()
- {
- increment = start < finish ? +1 : -1;
- }
-
- public boolean hasNext()
- {
- return hasNext;
- }
-
- public Integer next()
- {
- if (!hasNext) throw new IllegalStateException();
-
- int result = value;
-
- hasNext = value != finish;
-
- value += increment;
-
- return result;
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
-
- }
-
- public IntegerRange(final int start, final int finish)
- {
- this.start = start;
- this.finish = finish;
- }
-
- public int getFinish()
- {
- return finish;
- }
-
- public int getStart()
- {
- return start;
- }
-
- @Override
- public String toString()
- {
- return String.format("%d..%d", start, finish);
- }
-
- /**
- * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with
- * the Tapestry Loop component, but also with the Java for loop!
- */
- public Iterator<Integer> iterator()
- {
- return new RangeIterator();
- }
-
- @Override
- public int hashCode()
- {
- final int PRIME = 31;
-
- int result = PRIME + finish;
-
- result = PRIME * result + start;
-
- return result;
- }
-
- /**
- * Returns true if the other object is an IntegerRange with the same start and finish values.
- */
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- final IntegerRange other = (IntegerRange) obj;
- if (finish != other.finish) return false;
-
- return start == other.start;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
deleted file mode 100644
index 503bb1f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2006 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.util;
-
-import java.util.Arrays;
-
-/**
- * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested
- * maps.
- */
-public final class MultiKey
-{
- private static final int PRIME = 31;
-
- private final Object[] values;
-
- private final int hashCode;
-
- /**
- * Creates a new instance from the provided values. It is assumed that the values provided are good map keys
- * themselves -- immutable, with proper implementations of equals() and hashCode().
- *
- * @param values
- */
- public MultiKey(Object... values)
- {
- this.values = values;
-
- hashCode = PRIME * Arrays.hashCode(this.values);
- }
-
- @Override
- public int hashCode()
- {
- return hashCode;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- final MultiKey other = (MultiKey) obj;
-
- return Arrays.equals(values, other.values);
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder("MultiKey[");
-
- boolean first = true;
-
- for (Object o : values)
- {
- if (!first)
- builder.append(", ");
-
- builder.append(o);
-
- first = false;
- }
-
- builder.append("]");
-
- return builder.toString();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
deleted file mode 100644
index 16b4fca..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.services;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.ioc.Messages;
-
-/**
- * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
- * class. Also provides support to the model by generating validation information for individual fields.
- * <p/>
- * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
- * org.apache.tapestry5.corelib.components.Grid} comopnents.
- *
- * @see org.apache.tapestry5.services.PropertyConduitSource
- */
-public interface BeanModelSource
-{
- /**
- * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
- * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
- * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
- * properties are derived from the property names, but if the component's message catalog has keys of the form
- * <code>propertyName-label</code>, then those will be used instead.
- * <p/>
- * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
- *
- * @param beanClass class of object to be edited
- * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only
- * read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm},
- * etc.). If false, then both read-only and read-write properties will be included
- * (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link
- * org.apache.tapestry5.corelib.components.BeanDisplay}).
- * @param messages Used to find explicit overrides of
- * @return a model
- * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link
- * #createEditModel(Class, org.apache.tapestry5.ioc.Messages)}
- */
- <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages);
-
- /**
- * Creates a model for display purposes; this may include properties which are read-only.
- *
- * @param beanClass class of object to be edited
- * @param messages
- * @return a model containing properties that can be presented to the user
- */
- <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages);
-
- /**
- * Creates a model for edit and update purposes, only properties that are fully read-write are included.
- *
- * @param beanClass class of object to be edited
- * @param messages
- * @return a model containing properties that can be presented to the user
- */
- <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
deleted file mode 100644
index c901d3a..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2008, 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.services;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker annotation used to inject the correct {@link org.apache.tapestry5.services.InvalidationEventHub} service
- * responsible for invalidations when underlying component class files are changed.
- *
- * @since 5.1.0.0
- */
-@Target(
-{ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface ComponentClasses
-{
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
deleted file mode 100644
index e342c3f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.services;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * Marker annotation used to identify a service from the component layer that conflicts, in terms of service interface,
- * with a service from elsewhere. In particular, this is used to disambiguate {@link org.apache.tapestry5.ioc.services.PlasticProxyFactory} which has one implementation (marked with {@link
- * org.apache.tapestry5.ioc.services.Builtin} and another with this annotation.
- */
-@Target(
- {PARAMETER, FIELD})
-@Retention(RUNTIME)
-@Documented
-public @interface ComponentLayer
-{
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
deleted file mode 100644
index 77b028e..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2006, 2007, 2008, 2011, 2012 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.services;
-
-import java.util.Map;
-
-/**
- * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple
- * event hub services implementing this interface, each with a specific marker annotation; each can register listeners
- * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support
- * for:
- * <dl>
- * <dt>message catalog resources
- * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation
- * <dt>component templates
- * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation
- * <dt>component classes
- * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation
- * </dl>
- * <p/>
- * Starting in Tapestry 5.3, these services are disabled in production (it does nothing).
- *
- * @since 5.1.0.0
- */
-public interface InvalidationEventHub
-{
- /**
- * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the
- * receiver may discard any cached data that may have been invalidated). Does nothing in production mode.
- *
- * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead}
- */
- void addInvalidationListener(InvalidationListener listener);
-
- /**
- * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode.
- *
- * @since 5.4
- */
- void addInvalidationCallback(Runnable callback);
-
- /**
- * Adds a callback that clears the map.
- *
- * @since 5.4
- */
- void clearOnInvalidation(Map<?,?> map);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
deleted file mode 100644
index b9b4aa3..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2006, 2007, 2012 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.services;
-
-/**
- * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files,
- * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external
- * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as
- * necessary).
- *
- * @see org.apache.tapestry5.services.InvalidationEventHub
- * @since 5.1.0.0
- * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead
- */
-public interface InvalidationListener
-{
- /**
- * Invoked to indicate that some object is invalid. The receiver should clear its cache.
- */
- void objectWasInvalidated();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
deleted file mode 100644
index 312cd60..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2007, 2008, 2009 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.services;
-
-import org.apache.tapestry5.PropertyConduit;
-
-/**
- * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
- * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
- * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
- */
-public interface PropertyConduitSource
-{
- /**
- * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it
- * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if
- * a change to component classes is observed.
- * <p/>
- * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
- * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
- * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
- * and classloaders).
- *
- * @param rootType the type of the root object to which the expression is applied
- * @param expression expression to be evaluated on instances of the root class
- * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.)
- */
- PropertyConduit create(Class rootType, String expression);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-ioc/build.gradle b/tapestry-ioc/build.gradle
index e890f7e..5a5321f 100644
--- a/tapestry-ioc/build.gradle
+++ b/tapestry-ioc/build.gradle
@@ -4,6 +4,7 @@ dependencies {
compile project(':tapestry-func')
compile project(':tapestry5-annotations')
compile project(":plastic")
+ compile project(":beanmodel")
provided project(':tapestry-test')
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
deleted file mode 100644
index 1f0e744..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2007, 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.ioc;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method,
- * a Class, or some other source).
- */
-public interface AnnotationProvider
-{
- /**
- * Searches for the specified annotation, returning the matching annotation instance.
- *
- * @param <T>
- * @param annotationClass used to select the annotation to return
- * @return the annotation, or null if not found
- */
- <T extends Annotation> T getAnnotation(Class<T> annotationClass);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
deleted file mode 100644
index 37b6551..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2006, 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.ioc;
-
-/**
- * Interface implemented by objects which carry a location tag. Defines a readable property, location.
- */
-@SuppressWarnings({"JavaDoc"})
-public interface Locatable
-{
- /**
- * Returns the location associated with this object for error reporting purposes.
- */
- Location getLocation();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
deleted file mode 100644
index e6688c2..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2006 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.ioc;
-
-/**
- * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line
- * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be
- * tracked backwards to the files from which they were parsed or otherwise constructed.
- */
-public interface Location
-{
- /**
- * The resource from which the object tagged with a location was derived.
- */
- Resource getResource();
-
- /**
- * The line number within the resource, if known, or -1 otherwise.
- */
- int getLine();
-
- /**
- * The column number within the line if known, or -1 otherwise.
- */
- int getColumn();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
deleted file mode 100644
index e90eb65..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2006 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.ioc;
-
-/**
- * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message
- * key.
- */
-public interface MessageFormatter
-{
- /**
- * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of
- * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of
- * the class).
- *
- * @param args
- * @return formatted string
- */
- String format(Object... args);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
deleted file mode 100644
index ba7452c..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2006, 2007, 2012 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.ioc;
-
-import java.util.Set;
-
-/**
- * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
- * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
- * java.util.ResourceBundle} with some changes.
- */
-public interface Messages
-{
- /**
- * Returns true if the bundle contains the named key.
- */
- boolean contains(String key);
-
- /**
- * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version
- * of the key is returned (converted to upper case and enclosed in brackets).
- *
- * @param key
- * @return localized message for key, or placeholder
- */
- String get(String key);
-
- /**
- * Returns a formatter for the message, which can be used to substitute arguments (as per {@link
- * java.util.Formatter}).
- *
- * @param key
- * @return formattable object
- */
- MessageFormatter getFormatter(String key);
-
- /**
- * Convenience for accessing a formatter and formatting a localized message with arguments.
- */
- String format(String key, Object... args);
-
- /**
- * Returns a set of all the keys for which this instance may provide a value.
- *
- * @return set of keys
- * @since 5.4
- */
- Set<String> getKeys();
-}
[07/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
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/f963c7ab
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/f963c7ab
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/f963c7ab
Branch: refs/heads/beanmodel-split
Commit: f963c7ab7ebaf1b4b0349c9875a5490a85d75dd0
Parents: 09a011c
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 15:16:02 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 15:16:02 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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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/f963c7ab/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);
+ }
+}
[11/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index 8f1f7b6..a5f55b7 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,7 +17,6 @@ package org.apache.tapestry5.ioc.internal.util;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.func.Mapper;
import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
@@ -80,11 +79,10 @@ public class InternalUtils
*
* @param method
* @return short string representation
- * @deprecated use {@link InternalStringUtils#asString(Method)} instead.
*/
public static String asString(Method method)
{
- return InternalStringUtils.asString(method);
+ return InternalCommonsUtils.asString(method);
}
/**
@@ -103,11 +101,10 @@ public class InternalUtils
/**
* Strips leading "_" and "$" and trailing "_" from the name.
- * @deprecated use {@link InternalStringUtils#stripMemberName(String)} instead.
*/
public static String stripMemberName(String memberName)
{
- return InternalStringUtils.stripMemberName(memberName);
+ return InternalCommonsUtils.stripMemberName(memberName);
}
/**
@@ -392,11 +389,10 @@ public class InternalUtils
/**
* Joins together some number of elements to form a comma separated list.
- * @deprecated use {@link InternalStringUtils#join(List)} instead.
*/
public static String join(List elements)
{
- return InternalStringUtils.join(elements);
+ return InternalCommonsUtils.join(elements);
}
/**
@@ -407,11 +403,10 @@ public class InternalUtils
* objects to be joined together
* @param separator
* used between elements when joining
- * @deprecated use {@link InternalStringUtils#asString(Method, String)} instead.
*/
public static String join(List elements, String separator)
{
- return InternalStringUtils.join(elements, separator);
+ return InternalCommonsUtils.join(elements, separator);
}
/**
@@ -419,21 +414,19 @@ public class InternalUtils
*
* @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
* empty
- * @deprecated use {@link InternalStringUtils#joinSorted(Collection)} instead.
*/
public static String joinSorted(Collection elements)
{
- return InternalStringUtils.joinSorted(elements);
+ return InternalCommonsUtils.joinSorted(elements);
}
/**
* Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
- * @deprecated use {@link InternalStringUtils#isBlank(String)} instead.
*/
public static boolean isBlank(String input)
{
- return InternalStringUtils.isBlank(input);
+ return InternalCommonsUtils.isBlank(input);
}
/**
@@ -450,63 +443,27 @@ public class InternalUtils
return false;
}
- /**
- * @deprecated use {@link InternalStringUtils#isNonBlank(String)} instead.
- */
public static boolean isNonBlank(String input)
{
- return InternalStringUtils.isNonBlank(input);
+ return InternalCommonsUtils.isNonBlank(input);
}
/**
* Capitalizes a string, converting the first character to uppercase.
- * @deprecated use {@link InternalStringUtils#capitalize(String)} instead.
*/
public static String capitalize(String input)
{
- return InternalStringUtils.capitalize(input);
+ return InternalCommonsUtils.capitalize(input);
}
/**
* Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
* convertable to a location.
*/
-
+
public static Location locationOf(Object location)
{
- if (location == null)
- return null;
-
- if (location instanceof Location)
- return (Location) location;
-
- if (location instanceof Locatable)
- return ((Locatable) location).getLocation();
-
- return null;
- }
-
- /**
- * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
- *
- * @param map
- * the map to extract keys from (may be null)
- * @return the sorted keys, or the empty set if map is null
- */
-
- public static List<String> sortedKeys(Map map)
- {
- if (map == null)
- return Collections.emptyList();
-
- List<String> keys = CollectionFactory.newList();
-
- for (Object o : map.keySet())
- keys.add(String.valueOf(o));
-
- Collections.sort(keys);
-
- return keys;
+ return InternalCommonsUtils.locationOf(location);
}
public static <K, V> Set<K> keys(Map<K, V> map)
@@ -572,11 +529,10 @@ public class InternalUtils
/**
* Return true if the input string contains the marker for symbols that must be expanded.
- * @deprecated use {@link InternalStringUtils#containsSymbols(String)} instead.
*/
public static boolean containsSymbols(String input)
{
- return InternalStringUtils.containsSymbols(input);
+ return InternalCommonsUtils.containsSymbols(input);
}
/**
@@ -584,11 +540,10 @@ public class InternalUtils
* generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
* expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
* character.
- * @deprecated use {@link InternalStringUtils#lastTerm(String)} instead.
*/
public static String lastTerm(String input)
{
- return InternalStringUtils.lastTerm(input);
+ return InternalCommonsUtils.lastTerm(input);
}
/**
@@ -684,15 +639,7 @@ public class InternalUtils
*/
public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
{
- List<V> list = map.get(key);
-
- if (list == null)
- {
- list = CollectionFactory.newList();
- map.put(key, list);
- }
-
- list.add(value);
+ InternalCommonsUtils.addToMapList(map, key, value);
}
/**
@@ -777,7 +724,7 @@ public class InternalUtils
*/
public static AnnotationProvider toAnnotationProvider(final Class element)
{
- return InternalBeanModelUtils.toAnnotationProvider(element);
+ return InternalCommonsUtils.toAnnotationProvider(element);
}
/**
@@ -1392,7 +1339,7 @@ public class InternalUtils
{
String value = namedAnnotation.value();
- if (InternalUtils.isNonBlank(value))
+ if (InternalCommonsUtils.isNonBlank(value))
{
return value;
}
@@ -1404,7 +1351,7 @@ public class InternalUtils
public static AnnotationProvider toAnnotationProvider(final Method element)
{
- return InternalBeanModelUtils.toAnnotationProvider(element);
+ return InternalCommonsUtils.toAnnotationProvider(element);
}
public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,
@@ -1567,7 +1514,7 @@ public class InternalUtils
@Override
public void run()
{
- final ObjectCreator[] parameters = InternalUtils.calculateParametersForMethod(method, locator,
+ final ObjectCreator[] parameters = calculateParametersForMethod(method, locator,
resources, tracker);
plan.add(new InitializationPlan<Object>()
@@ -1651,4 +1598,55 @@ public class InternalUtils
{
return F.flow(creators).map(CREATE_OBJECT).toArray(Object.class);
}
+
+ /**
+ * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+ *
+ * @param map
+ * the map to extract keys from (may be null)
+ * @return the sorted keys, or the empty set if map is null
+ */
+
+ public static List<String> sortedKeys(Map map)
+ {
+ return InternalCommonsUtils.sortedKeys(map);
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ return InternalCommonsUtils.toUserPresentable(id);
+ }
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return InternalCommonsUtils.extractIdFromPropertyExpression(expression);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ return InternalCommonsUtils.defaultLabel(id, messages, propertyExpression);
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return InternalCommonsUtils.replace(input, pattern, replacement);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
deleted file mode 100644
index 41de363..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2012 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.ioc.internal.util;
-
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Base class for classes that need to manage a ReadWriteLock.
- */
-public abstract class LockSupport
-{
- private final Lock readLock, writeLock;
-
- protected LockSupport()
- {
- ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
- readLock = lock.readLock();
- writeLock = lock.writeLock();
- }
-
- /**
- * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
- */
- protected final void acquireReadLock()
- {
- readLock.lock();
- }
-
- /**
- * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
- * this thread will have locked the write lock and no other thread will have either the read or write lock.
- * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
- */
- protected final void takeWriteLock()
- {
- writeLock.lock();
- }
-
- /**
- * Releases the shared read lock.
- */
- protected final void releaseReadLock()
- {
- readLock.unlock();
- }
-
- /**
- * Releases the exclusive read lock.
- */
- protected final void releaseWriteLock()
- {
- writeLock.unlock();
- }
-
- /**
- * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
- * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
- * inside the code that has the write lock to see if the update to perform is still necessary.
- */
- protected final void upgradeReadLockToWriteLock()
- {
- releaseReadLock();
- // This is that instant where another thread may grab the write lock. Very rare, but possible.
- takeWriteLock();
- }
-
- /**
- * Takes the read lock then releases the write lock.
- */
- protected final void downgradeWriteLockToReadLock()
- {
- acquireReadLock();
- releaseWriteLock();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
deleted file mode 100644
index f4d8949..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2006-2013 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.ioc.internal.util;
-
-import org.apache.tapestry5.ioc.MessageFormatter;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-
-import java.util.Locale;
-
-
-public class MessageFormatterImpl implements MessageFormatter
-{
- private final String format;
-
- private final Locale locale;
-
- public MessageFormatterImpl(String format, Locale locale)
- {
- this.format = format;
- this.locale = locale;
- }
-
- @Override
- public String format(Object... args)
- {
- for (int i = 0; i < args.length; i++)
- {
- Object arg = args[i];
-
- if (Throwable.class.isInstance(arg))
- {
- args[i] = ExceptionUtils.toMessage((Throwable) arg);
- }
- }
-
- // Might be tempting to create a Formatter object and just keep reusing it ... but
- // Formatters are not threadsafe.
-
- return String.format(locale, format, args);
- }
-
- /**
- * Returns the underlying format string for this formatter.
- *
- * @since 5.4
- */
- @Override
- public String toString()
- {
- return format;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
deleted file mode 100644
index c06ef90..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2006, 2012 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.ioc.internal.util;
-
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.util.AbstractMessages;
-
-import java.util.*;
-
-/**
- * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
- */
-public class MessagesImpl extends AbstractMessages
-{
- private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
-
- /**
- * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
- * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
- *
- * @param forClass
- * @return Messages for the class
- */
- public static Messages forClass(Class forClass)
- {
- String className = forClass.getName();
- String stringsClassName = className.replaceAll("Messages$", "Strings");
-
- Locale locale = Locale.getDefault();
-
- ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
-
- return new MessagesImpl(locale, bundle);
- }
-
- public MessagesImpl(Locale locale, ResourceBundle bundle)
- {
- super(locale);
-
- // Our best (threadsafe) chance to determine all the available keys.
- Enumeration<String> e = bundle.getKeys();
- while (e.hasMoreElements())
- {
- String key = e.nextElement();
- String value = bundle.getString(key);
-
- properties.put(key, value);
- }
- }
-
- @Override
- protected String valueForKey(String key)
- {
- return properties.get(key);
- }
-
- @Override
- public Set<String> getKeys()
- {
- return properties.keySet();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
index a9af358..6d13d66 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
@@ -17,6 +17,7 @@ package org.apache.tapestry5.ioc.modules;
import org.apache.tapestry5.func.Flow;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
import org.apache.tapestry5.ioc.internal.services.*;
import org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
@@ -189,301 +190,9 @@ public final class TapestryIOCModule
@Contribute(TypeCoercer.class)
public static void provideBasicTypeCoercions(Configuration<CoercionTuple> configuration)
{
- add(configuration, Object.class, String.class, new Coercion<Object, String>()
- {
- @Override
- public String coerce(Object input)
- {
- return input.toString();
- }
- });
-
- add(configuration, Object.class, Boolean.class, new Coercion<Object, Boolean>()
- {
- @Override
- public Boolean coerce(Object input)
- {
- return input != null;
- }
- });
-
- add(configuration, String.class, Double.class, new Coercion<String, Double>()
- {
- @Override
- public Double coerce(String input)
- {
- return new Double(input);
- }
- });
-
- // String to BigDecimal is important, as String->Double->BigDecimal would lose
- // precision.
-
- add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>()
- {
- @Override
- public BigDecimal coerce(String input)
- {
- return new BigDecimal(input);
- }
- });
-
- add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>()
- {
- @Override
- public Double coerce(BigDecimal input)
- {
- return input.doubleValue();
- }
- });
-
- add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>()
- {
- @Override
- public BigInteger coerce(String input)
- {
- return new BigInteger(input);
- }
- });
-
- add(configuration, String.class, Long.class, new Coercion<String, Long>()
- {
- @Override
- public Long coerce(String input)
- {
- return new Long(input);
- }
- });
-
- add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
- {
- @Override
- public Byte coerce(Long input)
- {
- return input.byteValue();
- }
- });
-
- add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
- {
- @Override
- public Short coerce(Long input)
- {
- return input.shortValue();
- }
- });
-
- add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>()
- {
- @Override
- public Integer coerce(Long input)
- {
- return input.intValue();
- }
- });
-
- add(configuration, Number.class, Long.class, new Coercion<Number, Long>()
- {
- @Override
- public Long coerce(Number input)
- {
- return input.longValue();
- }
- });
-
- add(configuration, Double.class, Float.class, new Coercion<Double, Float>()
- {
- @Override
- public Float coerce(Double input)
- {
- return input.floatValue();
- }
- });
-
- add(configuration, Long.class, Double.class, new Coercion<Long, Double>()
- {
- @Override
- public Double coerce(Long input)
- {
- return input.doubleValue();
- }
- });
-
- add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>()
- {
- @Override
- public Boolean coerce(String input)
- {
- String trimmed = input == null ? "" : input.trim();
-
- if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
- return false;
-
- // Any non-blank string but "false"
-
- return true;
- }
- });
-
- add(configuration, Number.class, Boolean.class, new Coercion<Number, Boolean>()
- {
- @Override
- public Boolean coerce(Number input)
- {
- return input.longValue() != 0;
- }
- });
-
- add(configuration, Void.class, Boolean.class, new Coercion<Void, Boolean>()
- {
- @Override
- public Boolean coerce(Void input)
- {
- return false;
- }
- });
-
- add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
- {
- @Override
- public Boolean coerce(Collection input)
- {
- return !input.isEmpty();
- }
- });
-
- add(configuration, Object.class, List.class, new Coercion<Object, List>()
- {
- @Override
- public List coerce(Object input)
- {
- return Collections.singletonList(input);
- }
- });
-
- add(configuration, Object[].class, List.class, new Coercion<Object[], List>()
- {
- @Override
- public List coerce(Object[] input)
- {
- return Arrays.asList(input);
- }
- });
-
- add(configuration, Object[].class, Boolean.class, new Coercion<Object[], Boolean>()
- {
- @Override
- public Boolean coerce(Object[] input)
- {
- return input != null && input.length > 0;
- }
- });
-
- add(configuration, Float.class, Double.class, new Coercion<Float, Double>()
- {
- @Override
- public Double coerce(Float input)
- {
- return input.doubleValue();
- }
- });
-
- Coercion primitiveArrayCoercion = new Coercion<Object, List>()
- {
- @Override
- public List<Object> coerce(Object input)
- {
- int length = Array.getLength(input);
- Object[] array = new Object[length];
- for (int i = 0; i < length; i++)
- {
- array[i] = Array.get(input, i);
- }
- return Arrays.asList(array);
- }
- };
-
- add(configuration, byte[].class, List.class, primitiveArrayCoercion);
- add(configuration, short[].class, List.class, primitiveArrayCoercion);
- add(configuration, int[].class, List.class, primitiveArrayCoercion);
- add(configuration, long[].class, List.class, primitiveArrayCoercion);
- add(configuration, float[].class, List.class, primitiveArrayCoercion);
- add(configuration, double[].class, List.class, primitiveArrayCoercion);
- add(configuration, char[].class, List.class, primitiveArrayCoercion);
- add(configuration, boolean[].class, List.class, primitiveArrayCoercion);
-
- add(configuration, String.class, File.class, new Coercion<String, File>()
- {
- @Override
- public File coerce(String input)
- {
- return new File(input);
- }
- });
-
- add(configuration, String.class, TimeInterval.class, new Coercion<String, TimeInterval>()
- {
- @Override
- public TimeInterval coerce(String input)
- {
- return new TimeInterval(input);
- }
- });
-
- add(configuration, TimeInterval.class, Long.class, new Coercion<TimeInterval, Long>()
- {
- @Override
- public Long coerce(TimeInterval input)
- {
- return input.milliseconds();
- }
- });
-
- add(configuration, Object.class, Object[].class, new Coercion<Object, Object[]>()
- {
- @Override
- public Object[] coerce(Object input)
- {
- return new Object[]
- {input};
- }
- });
-
- add(configuration, Collection.class, Object[].class, new Coercion<Collection, Object[]>()
- {
- @Override
- public Object[] coerce(Collection input)
- {
- return input.toArray();
- }
- });
-
- add(configuration, Flow.class, List.class, new Coercion<Flow, List>()
- {
- @Override
- public List coerce(Flow input)
- {
- return input.toList();
- }
- });
-
- add(configuration, Flow.class, Boolean.class, new Coercion<Flow, Boolean>()
- {
- @Override
- public Boolean coerce(Flow input)
- {
- return !input.isEmpty();
- }
- });
-
+ BasicTypeCoercions.provideBasicTypeCoercions(configuration);
}
-
- private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
- Class<T> targetType, Coercion<S, T> coercion)
- {
- configuration.add(CoercionTuple.create(sourceType, targetType, coercion));
- }
-
+
/**
* <dl>
* <dt>SystemProperties</dt>
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
deleted file mode 100644
index 590c337..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2006, 2009, 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.ioc.util;
-
-import org.apache.tapestry5.ioc.MessageFormatter;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
-
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
- * a subclass, via the {@link #valueForKey(String)} method).
- */
-public abstract class AbstractMessages implements Messages
-{
- /**
- * String key to MF instance.
- */
- private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
-
- private final Locale locale;
-
- protected AbstractMessages(Locale locale)
- {
- this.locale = locale;
- }
-
- /**
- * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
- * implementation should <em>ignore the case of the key</em>.
- *
- * @param key the key to obtain a value for (case insensitive)
- * @return the value for the key, or null if this instance can not provide the value
- */
- protected abstract String valueForKey(String key);
-
-
- @Override
- public boolean contains(String key)
- {
- return valueForKey(key) != null;
- }
-
- @Override
- public String get(String key)
- {
- if (contains(key)) return valueForKey(key);
-
- return String.format("[[missing key: %s]]", key);
- }
-
- @Override
- public MessageFormatter getFormatter(String key)
- {
- MessageFormatter result = cache.get(key);
-
- if (result == null)
- {
- result = buildMessageFormatter(key);
- cache.put(key, result);
- }
-
- return result;
- }
-
- private MessageFormatter buildMessageFormatter(String key)
- {
- String format = get(key);
-
- return new MessageFormatterImpl(format, locale);
- }
-
- @Override
- public String format(String key, Object... args)
- {
- return getFormatter(key).format(args);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
deleted file mode 100644
index eaffe46..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
+++ /dev/null
@@ -1,195 +0,0 @@
-// 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.ioc.util;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
- * <p/>
- * TimePeriods are parsed from strings.
- * <p/>
- * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
- * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
- * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p> Example: "2 h 30 m". By
- * convention, terms are specified largest to smallest. A term without a unit is assumed to be milliseconds. Units are
- * case insensitive ("h" or "H" are treated the same).
- */
-public class TimeInterval
-{
- private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
-
- private static final long MILLISECOND = 1000l;
-
- static
- {
- UNITS.put("ms", 1l);
- UNITS.put("s", MILLISECOND);
- UNITS.put("m", 60 * MILLISECOND);
- UNITS.put("h", 60 * UNITS.get("m"));
- UNITS.put("d", 24 * UNITS.get("h"));
- UNITS.put("y", 365 * UNITS.get("d"));
- }
-
- /**
- * The unit keys, sorted in descending order.
- */
- private static final String[] UNIT_KEYS =
- { "y", "d", "h", "m", "s", "ms" };
-
- private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
-
- private final long milliseconds;
-
- /**
- * Creates a TimeInterval for a string.
- *
- * @param input
- * the string specifying the amount of time in the period
- */
- public TimeInterval(String input)
- {
- this(parseMilliseconds(input));
- }
-
- public TimeInterval(long milliseconds)
- {
- this.milliseconds = milliseconds;
- }
-
- public long milliseconds()
- {
- return milliseconds;
- }
-
- public long seconds()
- {
- return milliseconds / MILLISECOND;
- }
-
- /**
- * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
- *
- * @since 5.2.0
- */
- public String toDescription()
- {
- StringBuilder builder = new StringBuilder();
-
- String sep = "";
-
- long remainder = milliseconds;
-
- for (String key : UNIT_KEYS)
- {
- if (remainder == 0)
- break;
-
- long value = UNITS.get(key);
-
- long units = remainder / value;
-
- if (units > 0)
- {
- builder.append(sep);
- builder.append(units);
- builder.append(key);
-
- sep = " ";
-
- remainder = remainder % value;
- }
- }
-
- return builder.toString();
- }
-
- static long parseMilliseconds(String input)
- {
- long milliseconds = 0l;
-
- Matcher matcher = PATTERN.matcher(input);
-
- matcher.useAnchoringBounds(true);
-
- // TODO: Notice non matching characters and reject input, including at end
-
- int lastMatchEnd = -1;
-
- while (matcher.find())
- {
- int start = matcher.start();
-
- if (lastMatchEnd + 1 < start)
- {
- String invalid = input.substring(lastMatchEnd + 1, start);
- throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
- }
-
- lastMatchEnd = matcher.end();
-
- long count = Long.parseLong(matcher.group(1));
- String units = matcher.group(2);
-
- if (units.length() == 0)
- {
- milliseconds += count;
- continue;
- }
-
- Long unitValue = UNITS.get(units);
-
- if (unitValue == null)
- throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s'). Defined units: %s.", units, input, InternalUtils.joinSorted(UNITS.keySet())));
-
- milliseconds += count * unitValue;
- }
-
- if (lastMatchEnd + 1 < input.length())
- {
- String invalid = input.substring(lastMatchEnd + 1);
- throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
- }
-
- return milliseconds;
- }
-
- @Override
- public String toString()
- {
- return String.format("TimeInterval[%d ms]", milliseconds);
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (obj == null)
- return false;
-
- if (obj instanceof TimeInterval)
- {
- TimeInterval tp = (TimeInterval) obj;
-
- return milliseconds == tp.milliseconds;
- }
-
- return false;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
deleted file mode 100644
index 77c9a8d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.util;
-
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-
-/**
- * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
- * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
- * fashion.
- * <p>
- * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
- *
- * @param <T>
- * the type of enumeration
- */
-public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
-{
- private final Class<T> enumClass;
-
- private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
-
- public StringToEnumCoercion(Class<T> enumClass)
- {
- this(enumClass, enumClass.getEnumConstants());
- }
-
- public StringToEnumCoercion(Class<T> enumClass, T... values)
- {
- this.enumClass = enumClass;
-
- for (T value : values)
- stringToEnum.put(value.name(), value);
- }
-
- @Override
- public T coerce(String input)
- {
- if (InternalUtils.isBlank(input))
- return null;
-
- T result = stringToEnum.get(input);
-
- if (result == null)
- {
- String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
- enumClass.getName());
-
- throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
- stringToEnum));
- }
-
- return result;
- }
-
- /**
- * Allows an alias value (alternate) string to reference a value.
- *
- * @since 5.2.2
- */
- public StringToEnumCoercion<T> addAlias(String alias, T value)
- {
- stringToEnum.put(alias, value);
-
- return this;
- }
-
- public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
- {
- return new StringToEnumCoercion<T>(enumClass);
- }
-
-}
[11/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index 8f1f7b6..a5f55b7 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,7 +17,6 @@ package org.apache.tapestry5.ioc.internal.util;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.func.Mapper;
import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
@@ -80,11 +79,10 @@ public class InternalUtils
*
* @param method
* @return short string representation
- * @deprecated use {@link InternalStringUtils#asString(Method)} instead.
*/
public static String asString(Method method)
{
- return InternalStringUtils.asString(method);
+ return InternalCommonsUtils.asString(method);
}
/**
@@ -103,11 +101,10 @@ public class InternalUtils
/**
* Strips leading "_" and "$" and trailing "_" from the name.
- * @deprecated use {@link InternalStringUtils#stripMemberName(String)} instead.
*/
public static String stripMemberName(String memberName)
{
- return InternalStringUtils.stripMemberName(memberName);
+ return InternalCommonsUtils.stripMemberName(memberName);
}
/**
@@ -392,11 +389,10 @@ public class InternalUtils
/**
* Joins together some number of elements to form a comma separated list.
- * @deprecated use {@link InternalStringUtils#join(List)} instead.
*/
public static String join(List elements)
{
- return InternalStringUtils.join(elements);
+ return InternalCommonsUtils.join(elements);
}
/**
@@ -407,11 +403,10 @@ public class InternalUtils
* objects to be joined together
* @param separator
* used between elements when joining
- * @deprecated use {@link InternalStringUtils#asString(Method, String)} instead.
*/
public static String join(List elements, String separator)
{
- return InternalStringUtils.join(elements, separator);
+ return InternalCommonsUtils.join(elements, separator);
}
/**
@@ -419,21 +414,19 @@ public class InternalUtils
*
* @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
* empty
- * @deprecated use {@link InternalStringUtils#joinSorted(Collection)} instead.
*/
public static String joinSorted(Collection elements)
{
- return InternalStringUtils.joinSorted(elements);
+ return InternalCommonsUtils.joinSorted(elements);
}
/**
* Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
- * @deprecated use {@link InternalStringUtils#isBlank(String)} instead.
*/
public static boolean isBlank(String input)
{
- return InternalStringUtils.isBlank(input);
+ return InternalCommonsUtils.isBlank(input);
}
/**
@@ -450,63 +443,27 @@ public class InternalUtils
return false;
}
- /**
- * @deprecated use {@link InternalStringUtils#isNonBlank(String)} instead.
- */
public static boolean isNonBlank(String input)
{
- return InternalStringUtils.isNonBlank(input);
+ return InternalCommonsUtils.isNonBlank(input);
}
/**
* Capitalizes a string, converting the first character to uppercase.
- * @deprecated use {@link InternalStringUtils#capitalize(String)} instead.
*/
public static String capitalize(String input)
{
- return InternalStringUtils.capitalize(input);
+ return InternalCommonsUtils.capitalize(input);
}
/**
* Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
* convertable to a location.
*/
-
+
public static Location locationOf(Object location)
{
- if (location == null)
- return null;
-
- if (location instanceof Location)
- return (Location) location;
-
- if (location instanceof Locatable)
- return ((Locatable) location).getLocation();
-
- return null;
- }
-
- /**
- * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
- *
- * @param map
- * the map to extract keys from (may be null)
- * @return the sorted keys, or the empty set if map is null
- */
-
- public static List<String> sortedKeys(Map map)
- {
- if (map == null)
- return Collections.emptyList();
-
- List<String> keys = CollectionFactory.newList();
-
- for (Object o : map.keySet())
- keys.add(String.valueOf(o));
-
- Collections.sort(keys);
-
- return keys;
+ return InternalCommonsUtils.locationOf(location);
}
public static <K, V> Set<K> keys(Map<K, V> map)
@@ -572,11 +529,10 @@ public class InternalUtils
/**
* Return true if the input string contains the marker for symbols that must be expanded.
- * @deprecated use {@link InternalStringUtils#containsSymbols(String)} instead.
*/
public static boolean containsSymbols(String input)
{
- return InternalStringUtils.containsSymbols(input);
+ return InternalCommonsUtils.containsSymbols(input);
}
/**
@@ -584,11 +540,10 @@ public class InternalUtils
* generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
* expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
* character.
- * @deprecated use {@link InternalStringUtils#lastTerm(String)} instead.
*/
public static String lastTerm(String input)
{
- return InternalStringUtils.lastTerm(input);
+ return InternalCommonsUtils.lastTerm(input);
}
/**
@@ -684,15 +639,7 @@ public class InternalUtils
*/
public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
{
- List<V> list = map.get(key);
-
- if (list == null)
- {
- list = CollectionFactory.newList();
- map.put(key, list);
- }
-
- list.add(value);
+ InternalCommonsUtils.addToMapList(map, key, value);
}
/**
@@ -777,7 +724,7 @@ public class InternalUtils
*/
public static AnnotationProvider toAnnotationProvider(final Class element)
{
- return InternalBeanModelUtils.toAnnotationProvider(element);
+ return InternalCommonsUtils.toAnnotationProvider(element);
}
/**
@@ -1392,7 +1339,7 @@ public class InternalUtils
{
String value = namedAnnotation.value();
- if (InternalUtils.isNonBlank(value))
+ if (InternalCommonsUtils.isNonBlank(value))
{
return value;
}
@@ -1404,7 +1351,7 @@ public class InternalUtils
public static AnnotationProvider toAnnotationProvider(final Method element)
{
- return InternalBeanModelUtils.toAnnotationProvider(element);
+ return InternalCommonsUtils.toAnnotationProvider(element);
}
public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,
@@ -1567,7 +1514,7 @@ public class InternalUtils
@Override
public void run()
{
- final ObjectCreator[] parameters = InternalUtils.calculateParametersForMethod(method, locator,
+ final ObjectCreator[] parameters = calculateParametersForMethod(method, locator,
resources, tracker);
plan.add(new InitializationPlan<Object>()
@@ -1651,4 +1598,55 @@ public class InternalUtils
{
return F.flow(creators).map(CREATE_OBJECT).toArray(Object.class);
}
+
+ /**
+ * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+ *
+ * @param map
+ * the map to extract keys from (may be null)
+ * @return the sorted keys, or the empty set if map is null
+ */
+
+ public static List<String> sortedKeys(Map map)
+ {
+ return InternalCommonsUtils.sortedKeys(map);
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ return InternalCommonsUtils.toUserPresentable(id);
+ }
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return InternalCommonsUtils.extractIdFromPropertyExpression(expression);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ return InternalCommonsUtils.defaultLabel(id, messages, propertyExpression);
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return InternalCommonsUtils.replace(input, pattern, replacement);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
deleted file mode 100644
index 41de363..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2012 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.ioc.internal.util;
-
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Base class for classes that need to manage a ReadWriteLock.
- */
-public abstract class LockSupport
-{
- private final Lock readLock, writeLock;
-
- protected LockSupport()
- {
- ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
- readLock = lock.readLock();
- writeLock = lock.writeLock();
- }
-
- /**
- * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
- */
- protected final void acquireReadLock()
- {
- readLock.lock();
- }
-
- /**
- * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
- * this thread will have locked the write lock and no other thread will have either the read or write lock.
- * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
- */
- protected final void takeWriteLock()
- {
- writeLock.lock();
- }
-
- /**
- * Releases the shared read lock.
- */
- protected final void releaseReadLock()
- {
- readLock.unlock();
- }
-
- /**
- * Releases the exclusive read lock.
- */
- protected final void releaseWriteLock()
- {
- writeLock.unlock();
- }
-
- /**
- * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
- * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
- * inside the code that has the write lock to see if the update to perform is still necessary.
- */
- protected final void upgradeReadLockToWriteLock()
- {
- releaseReadLock();
- // This is that instant where another thread may grab the write lock. Very rare, but possible.
- takeWriteLock();
- }
-
- /**
- * Takes the read lock then releases the write lock.
- */
- protected final void downgradeWriteLockToReadLock()
- {
- acquireReadLock();
- releaseWriteLock();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
deleted file mode 100644
index f4d8949..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2006-2013 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.ioc.internal.util;
-
-import org.apache.tapestry5.ioc.MessageFormatter;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-
-import java.util.Locale;
-
-
-public class MessageFormatterImpl implements MessageFormatter
-{
- private final String format;
-
- private final Locale locale;
-
- public MessageFormatterImpl(String format, Locale locale)
- {
- this.format = format;
- this.locale = locale;
- }
-
- @Override
- public String format(Object... args)
- {
- for (int i = 0; i < args.length; i++)
- {
- Object arg = args[i];
-
- if (Throwable.class.isInstance(arg))
- {
- args[i] = ExceptionUtils.toMessage((Throwable) arg);
- }
- }
-
- // Might be tempting to create a Formatter object and just keep reusing it ... but
- // Formatters are not threadsafe.
-
- return String.format(locale, format, args);
- }
-
- /**
- * Returns the underlying format string for this formatter.
- *
- * @since 5.4
- */
- @Override
- public String toString()
- {
- return format;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
deleted file mode 100644
index c06ef90..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2006, 2012 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.ioc.internal.util;
-
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.util.AbstractMessages;
-
-import java.util.*;
-
-/**
- * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
- */
-public class MessagesImpl extends AbstractMessages
-{
- private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
-
- /**
- * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
- * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
- *
- * @param forClass
- * @return Messages for the class
- */
- public static Messages forClass(Class forClass)
- {
- String className = forClass.getName();
- String stringsClassName = className.replaceAll("Messages$", "Strings");
-
- Locale locale = Locale.getDefault();
-
- ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
-
- return new MessagesImpl(locale, bundle);
- }
-
- public MessagesImpl(Locale locale, ResourceBundle bundle)
- {
- super(locale);
-
- // Our best (threadsafe) chance to determine all the available keys.
- Enumeration<String> e = bundle.getKeys();
- while (e.hasMoreElements())
- {
- String key = e.nextElement();
- String value = bundle.getString(key);
-
- properties.put(key, value);
- }
- }
-
- @Override
- protected String valueForKey(String key)
- {
- return properties.get(key);
- }
-
- @Override
- public Set<String> getKeys()
- {
- return properties.keySet();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
index a9af358..6d13d66 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java
@@ -17,6 +17,7 @@ package org.apache.tapestry5.ioc.modules;
import org.apache.tapestry5.func.Flow;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
+import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
import org.apache.tapestry5.ioc.internal.services.*;
import org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
@@ -189,301 +190,9 @@ public final class TapestryIOCModule
@Contribute(TypeCoercer.class)
public static void provideBasicTypeCoercions(Configuration<CoercionTuple> configuration)
{
- add(configuration, Object.class, String.class, new Coercion<Object, String>()
- {
- @Override
- public String coerce(Object input)
- {
- return input.toString();
- }
- });
-
- add(configuration, Object.class, Boolean.class, new Coercion<Object, Boolean>()
- {
- @Override
- public Boolean coerce(Object input)
- {
- return input != null;
- }
- });
-
- add(configuration, String.class, Double.class, new Coercion<String, Double>()
- {
- @Override
- public Double coerce(String input)
- {
- return new Double(input);
- }
- });
-
- // String to BigDecimal is important, as String->Double->BigDecimal would lose
- // precision.
-
- add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>()
- {
- @Override
- public BigDecimal coerce(String input)
- {
- return new BigDecimal(input);
- }
- });
-
- add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>()
- {
- @Override
- public Double coerce(BigDecimal input)
- {
- return input.doubleValue();
- }
- });
-
- add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>()
- {
- @Override
- public BigInteger coerce(String input)
- {
- return new BigInteger(input);
- }
- });
-
- add(configuration, String.class, Long.class, new Coercion<String, Long>()
- {
- @Override
- public Long coerce(String input)
- {
- return new Long(input);
- }
- });
-
- add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
- {
- @Override
- public Byte coerce(Long input)
- {
- return input.byteValue();
- }
- });
-
- add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
- {
- @Override
- public Short coerce(Long input)
- {
- return input.shortValue();
- }
- });
-
- add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>()
- {
- @Override
- public Integer coerce(Long input)
- {
- return input.intValue();
- }
- });
-
- add(configuration, Number.class, Long.class, new Coercion<Number, Long>()
- {
- @Override
- public Long coerce(Number input)
- {
- return input.longValue();
- }
- });
-
- add(configuration, Double.class, Float.class, new Coercion<Double, Float>()
- {
- @Override
- public Float coerce(Double input)
- {
- return input.floatValue();
- }
- });
-
- add(configuration, Long.class, Double.class, new Coercion<Long, Double>()
- {
- @Override
- public Double coerce(Long input)
- {
- return input.doubleValue();
- }
- });
-
- add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>()
- {
- @Override
- public Boolean coerce(String input)
- {
- String trimmed = input == null ? "" : input.trim();
-
- if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
- return false;
-
- // Any non-blank string but "false"
-
- return true;
- }
- });
-
- add(configuration, Number.class, Boolean.class, new Coercion<Number, Boolean>()
- {
- @Override
- public Boolean coerce(Number input)
- {
- return input.longValue() != 0;
- }
- });
-
- add(configuration, Void.class, Boolean.class, new Coercion<Void, Boolean>()
- {
- @Override
- public Boolean coerce(Void input)
- {
- return false;
- }
- });
-
- add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
- {
- @Override
- public Boolean coerce(Collection input)
- {
- return !input.isEmpty();
- }
- });
-
- add(configuration, Object.class, List.class, new Coercion<Object, List>()
- {
- @Override
- public List coerce(Object input)
- {
- return Collections.singletonList(input);
- }
- });
-
- add(configuration, Object[].class, List.class, new Coercion<Object[], List>()
- {
- @Override
- public List coerce(Object[] input)
- {
- return Arrays.asList(input);
- }
- });
-
- add(configuration, Object[].class, Boolean.class, new Coercion<Object[], Boolean>()
- {
- @Override
- public Boolean coerce(Object[] input)
- {
- return input != null && input.length > 0;
- }
- });
-
- add(configuration, Float.class, Double.class, new Coercion<Float, Double>()
- {
- @Override
- public Double coerce(Float input)
- {
- return input.doubleValue();
- }
- });
-
- Coercion primitiveArrayCoercion = new Coercion<Object, List>()
- {
- @Override
- public List<Object> coerce(Object input)
- {
- int length = Array.getLength(input);
- Object[] array = new Object[length];
- for (int i = 0; i < length; i++)
- {
- array[i] = Array.get(input, i);
- }
- return Arrays.asList(array);
- }
- };
-
- add(configuration, byte[].class, List.class, primitiveArrayCoercion);
- add(configuration, short[].class, List.class, primitiveArrayCoercion);
- add(configuration, int[].class, List.class, primitiveArrayCoercion);
- add(configuration, long[].class, List.class, primitiveArrayCoercion);
- add(configuration, float[].class, List.class, primitiveArrayCoercion);
- add(configuration, double[].class, List.class, primitiveArrayCoercion);
- add(configuration, char[].class, List.class, primitiveArrayCoercion);
- add(configuration, boolean[].class, List.class, primitiveArrayCoercion);
-
- add(configuration, String.class, File.class, new Coercion<String, File>()
- {
- @Override
- public File coerce(String input)
- {
- return new File(input);
- }
- });
-
- add(configuration, String.class, TimeInterval.class, new Coercion<String, TimeInterval>()
- {
- @Override
- public TimeInterval coerce(String input)
- {
- return new TimeInterval(input);
- }
- });
-
- add(configuration, TimeInterval.class, Long.class, new Coercion<TimeInterval, Long>()
- {
- @Override
- public Long coerce(TimeInterval input)
- {
- return input.milliseconds();
- }
- });
-
- add(configuration, Object.class, Object[].class, new Coercion<Object, Object[]>()
- {
- @Override
- public Object[] coerce(Object input)
- {
- return new Object[]
- {input};
- }
- });
-
- add(configuration, Collection.class, Object[].class, new Coercion<Collection, Object[]>()
- {
- @Override
- public Object[] coerce(Collection input)
- {
- return input.toArray();
- }
- });
-
- add(configuration, Flow.class, List.class, new Coercion<Flow, List>()
- {
- @Override
- public List coerce(Flow input)
- {
- return input.toList();
- }
- });
-
- add(configuration, Flow.class, Boolean.class, new Coercion<Flow, Boolean>()
- {
- @Override
- public Boolean coerce(Flow input)
- {
- return !input.isEmpty();
- }
- });
-
+ BasicTypeCoercions.provideBasicTypeCoercions(configuration);
}
-
- private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
- Class<T> targetType, Coercion<S, T> coercion)
- {
- configuration.add(CoercionTuple.create(sourceType, targetType, coercion));
- }
-
+
/**
* <dl>
* <dt>SystemProperties</dt>
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
deleted file mode 100644
index 590c337..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2006, 2009, 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.ioc.util;
-
-import org.apache.tapestry5.ioc.MessageFormatter;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
-
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
- * a subclass, via the {@link #valueForKey(String)} method).
- */
-public abstract class AbstractMessages implements Messages
-{
- /**
- * String key to MF instance.
- */
- private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
-
- private final Locale locale;
-
- protected AbstractMessages(Locale locale)
- {
- this.locale = locale;
- }
-
- /**
- * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
- * implementation should <em>ignore the case of the key</em>.
- *
- * @param key the key to obtain a value for (case insensitive)
- * @return the value for the key, or null if this instance can not provide the value
- */
- protected abstract String valueForKey(String key);
-
-
- @Override
- public boolean contains(String key)
- {
- return valueForKey(key) != null;
- }
-
- @Override
- public String get(String key)
- {
- if (contains(key)) return valueForKey(key);
-
- return String.format("[[missing key: %s]]", key);
- }
-
- @Override
- public MessageFormatter getFormatter(String key)
- {
- MessageFormatter result = cache.get(key);
-
- if (result == null)
- {
- result = buildMessageFormatter(key);
- cache.put(key, result);
- }
-
- return result;
- }
-
- private MessageFormatter buildMessageFormatter(String key)
- {
- String format = get(key);
-
- return new MessageFormatterImpl(format, locale);
- }
-
- @Override
- public String format(String key, Object... args)
- {
- return getFormatter(key).format(args);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
deleted file mode 100644
index eaffe46..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
+++ /dev/null
@@ -1,195 +0,0 @@
-// 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.ioc.util;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
- * <p/>
- * TimePeriods are parsed from strings.
- * <p/>
- * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
- * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
- * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p> Example: "2 h 30 m". By
- * convention, terms are specified largest to smallest. A term without a unit is assumed to be milliseconds. Units are
- * case insensitive ("h" or "H" are treated the same).
- */
-public class TimeInterval
-{
- private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
-
- private static final long MILLISECOND = 1000l;
-
- static
- {
- UNITS.put("ms", 1l);
- UNITS.put("s", MILLISECOND);
- UNITS.put("m", 60 * MILLISECOND);
- UNITS.put("h", 60 * UNITS.get("m"));
- UNITS.put("d", 24 * UNITS.get("h"));
- UNITS.put("y", 365 * UNITS.get("d"));
- }
-
- /**
- * The unit keys, sorted in descending order.
- */
- private static final String[] UNIT_KEYS =
- { "y", "d", "h", "m", "s", "ms" };
-
- private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
-
- private final long milliseconds;
-
- /**
- * Creates a TimeInterval for a string.
- *
- * @param input
- * the string specifying the amount of time in the period
- */
- public TimeInterval(String input)
- {
- this(parseMilliseconds(input));
- }
-
- public TimeInterval(long milliseconds)
- {
- this.milliseconds = milliseconds;
- }
-
- public long milliseconds()
- {
- return milliseconds;
- }
-
- public long seconds()
- {
- return milliseconds / MILLISECOND;
- }
-
- /**
- * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
- *
- * @since 5.2.0
- */
- public String toDescription()
- {
- StringBuilder builder = new StringBuilder();
-
- String sep = "";
-
- long remainder = milliseconds;
-
- for (String key : UNIT_KEYS)
- {
- if (remainder == 0)
- break;
-
- long value = UNITS.get(key);
-
- long units = remainder / value;
-
- if (units > 0)
- {
- builder.append(sep);
- builder.append(units);
- builder.append(key);
-
- sep = " ";
-
- remainder = remainder % value;
- }
- }
-
- return builder.toString();
- }
-
- static long parseMilliseconds(String input)
- {
- long milliseconds = 0l;
-
- Matcher matcher = PATTERN.matcher(input);
-
- matcher.useAnchoringBounds(true);
-
- // TODO: Notice non matching characters and reject input, including at end
-
- int lastMatchEnd = -1;
-
- while (matcher.find())
- {
- int start = matcher.start();
-
- if (lastMatchEnd + 1 < start)
- {
- String invalid = input.substring(lastMatchEnd + 1, start);
- throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
- }
-
- lastMatchEnd = matcher.end();
-
- long count = Long.parseLong(matcher.group(1));
- String units = matcher.group(2);
-
- if (units.length() == 0)
- {
- milliseconds += count;
- continue;
- }
-
- Long unitValue = UNITS.get(units);
-
- if (unitValue == null)
- throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s'). Defined units: %s.", units, input, InternalUtils.joinSorted(UNITS.keySet())));
-
- milliseconds += count * unitValue;
- }
-
- if (lastMatchEnd + 1 < input.length())
- {
- String invalid = input.substring(lastMatchEnd + 1);
- throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
- }
-
- return milliseconds;
- }
-
- @Override
- public String toString()
- {
- return String.format("TimeInterval[%d ms]", milliseconds);
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (obj == null)
- return false;
-
- if (obj instanceof TimeInterval)
- {
- TimeInterval tp = (TimeInterval) obj;
-
- return milliseconds == tp.milliseconds;
- }
-
- return false;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
deleted file mode 100644
index 77c9a8d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.util;
-
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-
-/**
- * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
- * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
- * fashion.
- * <p>
- * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
- *
- * @param <T>
- * the type of enumeration
- */
-public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
-{
- private final Class<T> enumClass;
-
- private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
-
- public StringToEnumCoercion(Class<T> enumClass)
- {
- this(enumClass, enumClass.getEnumConstants());
- }
-
- public StringToEnumCoercion(Class<T> enumClass, T... values)
- {
- this.enumClass = enumClass;
-
- for (T value : values)
- stringToEnum.put(value.name(), value);
- }
-
- @Override
- public T coerce(String input)
- {
- if (InternalUtils.isBlank(input))
- return null;
-
- T result = stringToEnum.get(input);
-
- if (result == null)
- {
- String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
- enumClass.getName());
-
- throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
- stringToEnum));
- }
-
- return result;
- }
-
- /**
- * Allows an alias value (alternate) string to reference a value.
- *
- * @since 5.2.2
- */
- public StringToEnumCoercion<T> addAlias(String alias, T value)
- {
- stringToEnum.put(alias, value);
-
- return this;
- }
-
- public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
- {
- return new StringToEnumCoercion<T>(enumClass);
- }
-
-}
[12/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
deleted file mode 100644
index 9151381..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2006, 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.ioc;
-
-/**
- * Object passed into a service contributor method that allows the method provide contributed values to the service's
- * configuration.
- * <p/>
- * A service can <em>collect</em> contributions in three different ways:
- * <ul>
- * <li>As an un-ordered collection of values</li>
- * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
- * <li>As a map of keys and values
- * </ul>
- * <p/>
- * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
- * must be compatible with the type, or be {@linkplain org.apache.tapestry5.ioc.services.TypeCoercer coercable} to the type.
- *
- * @see org.apache.tapestry5.ioc.annotations.Contribute
- * @see org.apache.tapestry5.ioc.annotations.UsesConfiguration
- */
-public interface OrderedConfiguration<T>
-{
- /**
- * Adds an ordered object to a service's contribution. Each object has an id (which must be unique). Optionally,
- * pre-requisites (a list of ids that must precede this object) and post-requisites (ids that must follow) can be
- * provided.
- * <p/>
- * <p>If no constraints are supplied, then an implicit constraint is supplied: after the previously
- * contributed id <em>within the same contribution method</em>.
- *
- * @param id a unique id for the object; the id will be fully qualified with the contributing module's id
- * @param constraints used to order the object relative to other contributed objects
- * @param object to add to the service's configuration
- */
- void add(String id, T object, String... constraints);
-
- /**
- * Overrides a normally contributed object. Each override must match a single normally contributed object.
- *
- * @param id identifies object to override
- * @param object overriding object (may be null)
- * @param constraints constraints for the overridden object, replacing constraints for the original object (even if
- * omitted, in which case the override object will have no ordering constraints)
- * @since 5.1.0.0
- */
- void override(String id, T object, String... constraints);
-
- /**
- * Adds an ordered object by instantiating (with dependencies) the indicated class. When the configuration type is
- * an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the class will be created and contributed.
- *
- * @param id of contribution (used for ordering)
- * @param clazz class to instantiate
- * @param constraints used to order the object relative to other contributed objects
- * @since 5.1.0.0
- */
- void addInstance(String id, Class<? extends T> clazz, String... constraints);
-
- /**
- * Instantiates an object and adds it as an override. When the configuration type is an interface and the class to
- * be contributed is a local file, then a reloadable proxy for the class will be created and contributed.
- *
- * @param id of object to override
- * @param clazz to instantiate
- * @param constraints constraints for the overridden object, replacing constraints for the original object (even if
- * omitted, in which case the override object will have no ordering constraints)
- * @since 5.1.0.0
- */
- void overrideInstance(String id, Class<? extends T> clazz, String... constraints);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
deleted file mode 100644
index 2acfd0d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AccessibleObject;
-
-/**
- * Provides access to annotations of an accessable object such as a {@link java.lang.reflect.Method} or {@link
- * java.lang.reflect.Field}.
- */
-public class AccessableObjectAnnotationProvider implements AnnotationProvider
-{
- private final AccessibleObject object;
-
- public AccessableObjectAnnotationProvider(AccessibleObject object)
- {
- this.object = object;
- }
-
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return object.getAnnotation(annotationClass);
- }
-
- @Override
- public String toString()
- {
- return String.format("AnnotationProvider[%s]", object);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
deleted file mode 100644
index 49b0b15..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-
-/**
- * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
- */
-public class AnnotationProviderChain implements AnnotationProvider
-{
- private final AnnotationProvider[] providers;
-
- public AnnotationProviderChain(AnnotationProvider[] providers)
- {
- this.providers = providers;
- }
-
- /**
- * Creates an AnnotationProvider from the list of providers. Returns either an {@link AnnotationProviderChain} or
- * the sole element in the list.
- */
- public static AnnotationProvider create(List<AnnotationProvider> providers)
- {
- int size = providers.size();
-
- if (size == 1) return providers.get(0);
-
- return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
- }
-
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- for (AnnotationProvider p : providers)
- {
- T result = p.getAnnotation(annotationClass);
-
- if (result != null) return result;
- }
-
- return null;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
deleted file mode 100644
index af4bd7d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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.ioc.internal.services;
-
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
-
-import java.beans.PropertyDescriptor;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-
-public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
-{
- private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap();
-
- private final Class beanType;
-
- public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> descriptors)
- {
- this.beanType = beanType;
-
- // lazy init
- Map<String, List<Method>> nonBridgeMethods = null;
-
- for (PropertyDescriptor pd : descriptors)
- {
- // Indexed properties will have a null propertyType (and a non-null
- // indexedPropertyType). We ignore indexed properties.
-
- final Class<?> thisPropertyType = pd.getPropertyType();
- if (thisPropertyType == null)
- continue;
-
- Method readMethod = pd.getReadMethod();
- Method writeMethod = pd.getWriteMethod();
-
- // TAP5-1493
- if (readMethod != null && readMethod.isBridge())
- {
- if (nonBridgeMethods == null)
- {
- nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
- }
- readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods);
- }
-
- // TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed
- if (readMethod == null) {
- final String prefix = thisPropertyType != boolean.class ? "get" : "is";
- try
- {
- Method method = beanType.getMethod(prefix + capitalize(pd.getName()));
- final Class<?> returnType = method.getReturnType();
- if (returnType.equals(thisPropertyType) || returnType.isInstance(thisPropertyType)) {
- readMethod = method;
- }
- }
- catch (SecurityException e) {
- // getter not usable.
- }
- catch (NoSuchMethodException e)
- {
- // getter doesn't exist.
- }
- }
-
- if (writeMethod != null && writeMethod.isBridge())
- {
- if (nonBridgeMethods == null)
- {
- nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
- }
- writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
- }
-
- // TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed
- if (writeMethod == null) {
- try
- {
- Method method = beanType.getMethod("set" + capitalize(pd.getName()), pd.getPropertyType());
- final Class<?> returnType = method.getReturnType();
- if (returnType.equals(void.class)) {
- writeMethod = method;
- }
- }
- catch (SecurityException e) {
- // setter not usable.
- }
- catch (NoSuchMethodException e)
- {
- // setter doesn't exist.
- }
- }
-
- Class propertyType = readMethod == null ? thisPropertyType : GenericsUtils.extractGenericReturnType(
- beanType, readMethod);
-
- PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, writeMethod);
-
- adapters.put(pa.getName(), pa);
- }
-
- // Now, add any public fields (even if static) that do not conflict
-
- for (Field f : beanType.getFields())
- {
- String name = f.getName();
-
- if (!adapters.containsKey(name))
- {
- Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f);
- PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f);
-
- adapters.put(name, pa);
- }
- }
- }
-
- private static String capitalize(String name)
- {
- return Character.toUpperCase(name.charAt(0)) + name.substring(1);
- }
-
- /**
- * Find a replacement for the method (if one exists)
- * @param method A method
- * @param groupedMethods Methods mapped by name
- * @return A method from groupedMethods with the same name / param count
- * (default to providedmethod if none found)
- */
- private Method findMethodWithSameNameAndParamCount(Method method, Map<String, List<Method>> groupedMethods) {
- List<Method> methodGroup = groupedMethods.get(method.getName());
- if (methodGroup != null)
- {
- for (Method nonBridgeMethod : methodGroup)
- {
- if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length)
- {
- // return the non-bridge method with the same name / argument count
- return nonBridgeMethod;
- }
- }
- }
-
- // default to the provided method
- return method;
- }
-
- /**
- * Find all of the public methods that are not bridge methods and
- * group them by method name
- *
- * {@see Method#isBridge()}
- * @param type Bean type
- * @return
- */
- private Map<String, List<Method>> groupNonBridgeMethodsByName(Class type)
- {
- Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap();
- for (Method method : type.getMethods())
- {
- if (!method.isBridge())
- {
- List<Method> methodGroup = methodGroupsByName.get(method.getName());
- if (methodGroup == null)
- {
- methodGroup = CollectionFactory.newList();
- methodGroupsByName.put(method.getName(), methodGroup);
- }
- methodGroup.add(method);
- }
- }
- return methodGroupsByName;
- }
-
- @Override
- public Class getBeanType()
- {
- return beanType;
- }
-
- @Override
- public String toString()
- {
- String names = InternalUtils.joinSorted(adapters.keySet());
-
- return String.format("<ClassPropertyAdaptor %s: %s>", beanType.getName(), names);
- }
-
- @Override
- public List<String> getPropertyNames()
- {
- return InternalUtils.sortedKeys(adapters);
- }
-
- @Override
- public PropertyAdapter getPropertyAdapter(String name)
- {
- return adapters.get(name);
- }
-
- @Override
- public Object get(Object instance, String propertyName)
- {
- return adaptorFor(propertyName).get(instance);
- }
-
- @Override
- public void set(Object instance, String propertyName, Object value)
- {
- adaptorFor(propertyName).set(instance, value);
- }
-
- @Override
- public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) {
- return adaptorFor(propertyName).getAnnotation(annotationClass);
- }
-
- private PropertyAdapter adaptorFor(String name)
- {
- PropertyAdapter pa = adapters.get(name);
-
- if (pa == null)
- throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
-
- return pa;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
deleted file mode 100644
index 4a5dece..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2006, 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.services.Coercion;
-
-/**
- * Combines two coercions to create a coercion through an intermediate type.
- *
- * @param <S> The source (input) type
- * @param <I> The intermediate type
- * @param <T> The target (output) type
- */
-public class CompoundCoercion<S, I, T> implements Coercion<S, T>
-{
- private final Coercion<S, I> op1;
-
- private final Coercion<I, T> op2;
-
- public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
- {
- this.op1 = op1;
- this.op2 = op2;
- }
-
- @Override
- public T coerce(S input)
- {
- // Run the input through the first operation (S --> I), then run the result of that through
- // the second operation (I --> T).
-
- I intermediate = op1.coerce(input);
-
- return op2.coerce(intermediate);
- }
-
- @Override
- public String toString()
- {
- return String.format("%s, %s", op1, op2);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
deleted file mode 100644
index 8ebdede..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 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.ioc.internal.services;
-
-import org.apache.tapestry5.plastic.ClassType;
-import org.apache.tapestry5.plastic.PlasticClassEvent;
-import org.apache.tapestry5.plastic.PlasticClassListener;
-import org.slf4j.Logger;
-import org.slf4j.Marker;
-import org.slf4j.MarkerFactory;
-
-public class PlasticClassListenerLogger implements PlasticClassListener
-{
- private final Logger logger;
-
- public PlasticClassListenerLogger(Logger logger)
- {
- this.logger = logger;
- }
-
- @Override
- public void classWillLoad(PlasticClassEvent event)
- {
- if (logger.isDebugEnabled())
- {
- Marker marker = MarkerFactory.getMarker(event.getPrimaryClassName());
-
- String extendedClassName = event.getType() == ClassType.PRIMARY ? event.getPrimaryClassName() : String
- .format("%s (%s for %s)", event.getClassName(), event.getType(), event.getPrimaryClassName());
-
- logger.debug(marker,
- String.format("Loading class %s:\n%s", extendedClassName, event.getDissasembledBytecode()));
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
deleted file mode 100644
index 112e29d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright 2011, 2012 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.ioc.internal.services;
-
-import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
-import org.apache.tapestry5.internal.plastic.asm.Type;
-import org.apache.tapestry5.internal.plastic.asm.tree.*;
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
-import org.apache.tapestry5.plastic.*;
-import org.slf4j.Logger;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
-
-public class PlasticProxyFactoryImpl implements PlasticProxyFactory
-{
- public static final String INTERNAL_GET_DELEGATE = "_____internalGetDelegate_DONT_CALL_THIS_METHOD_____";
-
- private final PlasticManager manager;
-
- private final Map<String, Location> memberToLocation = CollectionFactory.newConcurrentMap();
-
- public PlasticProxyFactoryImpl(ClassLoader parentClassLoader, Logger logger)
- {
- this(PlasticManager.withClassLoader(parentClassLoader).create(), logger);
- }
-
- public PlasticProxyFactoryImpl(PlasticManager manager, Logger logger)
- {
- assert manager != null;
-
- this.manager = manager;
-
- if (logger != null)
- {
- manager.addPlasticClassListener(new PlasticClassListenerLogger(logger));
- }
- }
-
- @Override
- public ClassLoader getClassLoader()
- {
- return manager.getClassLoader();
- }
-
- @Override
- public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback)
- {
- return manager.createProxy(interfaceType, implementationType, callback);
- }
-
- @Override
- public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
- {
- return manager.createProxy(interfaceType, callback);
- }
-
-
- @Override
- public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType,
- Class<? extends T> implementationType)
- {
- return manager.createProxyTransformation(interfaceType, implementationType);
- }
-
- @Override
- public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType)
- {
- return createProxyTransformation(interfaceType, null);
- }
-
- @Override
- public <T> T createProxy(final Class<T> interfaceType, final ObjectCreator<T> creator, final String description)
- { return createProxy(interfaceType, null, creator, description);
- }
-
- @Override
- public <T> T createProxy(final Class<T> interfaceType, final Class<? extends T> implementationType,
- final ObjectCreator<T> creator, final String description)
- {
- assert creator != null;
- assert InternalUtils.isNonBlank(description);
-
- ClassInstantiator<T> instantiator = createProxy(interfaceType, implementationType, new PlasticClassTransformer()
- {
- @Override
- public void transform(PlasticClass plasticClass)
- {
- final PlasticField objectCreatorField = plasticClass.introduceField(ObjectCreator.class, "creator")
- .inject(creator);
-
- final String interfaceTypeName = interfaceType.getName();
- PlasticMethod delegateMethod = plasticClass.introducePrivateMethod(interfaceTypeName, "delegate",
- null, null);
-
- final InstructionBuilderCallback returnCreateObject = new InstructionBuilderCallback()
- {
- @Override
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadThis().getField(objectCreatorField);
- builder.invoke(ObjectCreator.class, Object.class, "createObject");
- builder.checkcast(interfaceType).returnResult();
- }
- };
-
- delegateMethod.changeImplementation(returnCreateObject);
-
- for (Method method : interfaceType.getMethods())
- {
- plasticClass.introduceMethod(method).delegateTo(delegateMethod);
- }
-
- // TA5-2235
- MethodDescription getDelegateMethodDescription =
- new MethodDescription(interfaceType.getName(), INTERNAL_GET_DELEGATE);
- plasticClass.introduceMethod(getDelegateMethodDescription, returnCreateObject);
-
- plasticClass.addToString(description);
-
- }
- });
-
- return interfaceType.cast(instantiator.newInstance());
- }
-
- private ClassNode readClassNode(Class clazz)
- {
- byte[] bytecode = PlasticInternalUtils.readBytecodeForClass(manager.getClassLoader(), clazz.getName(), false);
-
- return bytecode == null ? null : PlasticInternalUtils.convertBytecodeToClassNode(bytecode);
- }
-
- @Override
- public Location getMethodLocation(final Method method)
- {
- ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
- {
- @Override
- public String createObject()
- {
- return InternalUtils.asString(method);
- }
- };
-
- return getMemberLocation(method, method.getName(), Type.getMethodDescriptor(method),
- descriptionCreator);
- }
-
- @Override
- public Location getConstructorLocation(final Constructor constructor)
- {
- ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
- {
- @Override
- public String createObject()
- {
- StringBuilder builder = new StringBuilder(constructor.getDeclaringClass().getName()).append("(");
- String sep = "";
-
- for (Class parameterType : constructor.getParameterTypes())
- {
- builder.append(sep);
- builder.append(parameterType.getSimpleName());
-
- sep = ", ";
- }
-
- builder.append(")");
-
- return builder.toString();
- }
- };
-
- return getMemberLocation(constructor, "<init>", Type.getConstructorDescriptor(constructor),
- descriptionCreator);
- }
-
- @Override
- public void clearCache()
- {
- memberToLocation.clear();
- }
-
-
- public Location getMemberLocation(Member member, String methodName, String memberTypeDesc, ObjectCreator<String> textDescriptionCreator)
- {
- String className = member.getDeclaringClass().getName();
-
- String key = className + ":" + methodName + ":" + memberTypeDesc;
-
- Location location = memberToLocation.get(key);
-
- if (location == null)
- {
- location = constructMemberLocation(member, methodName, memberTypeDesc, textDescriptionCreator.createObject());
-
- memberToLocation.put(key, location);
- }
-
- return location;
-
- }
-
- private Location constructMemberLocation(Member member, String methodName, String memberTypeDesc, String textDescription)
- {
-
- ClassNode classNode = readClassNode(member.getDeclaringClass());
-
- if (classNode == null)
- {
- throw new RuntimeException(String.format("Unable to read class file for %s (to gather line number information).",
- textDescription));
- }
-
- for (MethodNode mn : (List<MethodNode>) classNode.methods)
- {
- if (mn.name.equals(methodName) && mn.desc.equals(memberTypeDesc))
- {
- int lineNumber = findFirstLineNumber(mn.instructions);
-
- // If debugging info is not available, we may lose the line number data, in which case,
- // just generate the Location from the textDescription.
-
- if (lineNumber < 1)
- {
- break;
- }
-
- String description = String.format("%s (at %s:%d)", textDescription, classNode.sourceFile, lineNumber);
-
- return new StringLocation(description, lineNumber);
- }
- }
-
- // Didn't find it. Odd.
-
- return new StringLocation(textDescription, 0);
- }
-
- private int findFirstLineNumber(InsnList instructions)
- {
- for (AbstractInsnNode node = instructions.getFirst(); node != null; node = node.getNext())
- {
- if (node instanceof LineNumberNode)
- {
- return ((LineNumberNode) node).line;
- }
- }
-
- return -1;
- }
-
- @Override
- public void addPlasticClassListener(PlasticClassListener listener)
- {
- manager.addPlasticClassListener(listener);
- }
-
- @Override
- public void removePlasticClassListener(PlasticClassListener listener)
- {
- manager.removePlasticClassListener(listener);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
deleted file mode 100644
index 8dd1e02..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright 2006, 2007, 2008, 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.ioc.internal.services;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAccess;
-
-@SuppressWarnings("unchecked")
-public class PropertyAccessImpl implements PropertyAccess
-{
- private final Map<Class, ClassPropertyAdapter> adapters = CollectionFactory.newConcurrentMap();
-
- @Override
- public Object get(Object instance, String propertyName)
- {
- return getAdapter(instance).get(instance, propertyName);
- }
-
- @Override
- public void set(Object instance, String propertyName, Object value)
- {
- getAdapter(instance).set(instance, propertyName, value);
- }
-
- @Override
- public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) {
- return getAdapter(instance).getAnnotation(instance, propertyName, annotationClass);
- }
-
-
- /**
- * Clears the cache of adapters and asks the {@link Introspector} to clear its cache.
- */
- @Override
- public synchronized void clearCache()
- {
- adapters.clear();
-
- Introspector.flushCaches();
- }
-
- @Override
- public ClassPropertyAdapter getAdapter(Object instance)
- {
- return getAdapter(instance.getClass());
- }
-
- @Override
- public ClassPropertyAdapter getAdapter(Class forClass)
- {
- ClassPropertyAdapter result = adapters.get(forClass);
-
- if (result == null)
- {
- result = buildAdapter(forClass);
- adapters.put(forClass, result);
- }
-
- return result;
- }
-
- /**
- * Builds a new adapter and updates the _adapters cache. This not only guards access to the adapter cache, but also
- * serializes access to the Java Beans Introspector, which is not thread safe. In addition, handles the case where
- * the class in question is an interface, accumulating properties inherited from super-classes.
- */
- private synchronized ClassPropertyAdapter buildAdapter(Class forClass)
- {
- // In some race conditions, we may hit this method for the same class multiple times.
- // We just let it happen, replacing the old ClassPropertyAdapter with a new one.
-
- try
- {
- BeanInfo info = Introspector.getBeanInfo(forClass);
-
- List<PropertyDescriptor> descriptors = CollectionFactory.newList();
-
- addAll(descriptors, info.getPropertyDescriptors());
-
- // TAP5-921 - Introspector misses interface methods not implemented in an abstract class
- if (forClass.isInterface() || Modifier.isAbstract(forClass.getModifiers()) )
- addPropertiesFromExtendedInterfaces(forClass, descriptors);
-
- addPropertiesFromScala(forClass, descriptors);
-
- return new ClassPropertyAdapterImpl(forClass, descriptors);
- }
- catch (Throwable ex)
- {
- throw new RuntimeException(ex);
- }
- }
-
- private <T> void addAll(List<T> list, T[] array)
- {
- list.addAll(Arrays.asList(array));
- }
-
- private void addPropertiesFromExtendedInterfaces(Class forClass, List<PropertyDescriptor> descriptors)
- throws IntrospectionException
- {
- LinkedList<Class> queue = CollectionFactory.newLinkedList();
-
- // Seed the queue
- addAll(queue, forClass.getInterfaces());
-
- while (!queue.isEmpty())
- {
- Class c = queue.removeFirst();
-
- BeanInfo info = Introspector.getBeanInfo(c);
-
- // Duplicates occur and are filtered out in ClassPropertyAdapter which stores
- // a property name to descriptor map.
- addAll(descriptors, info.getPropertyDescriptors());
- addAll(queue, c.getInterfaces());
- }
- }
-
- private void addPropertiesFromScala(Class forClass, List<PropertyDescriptor> descriptors)
- throws IntrospectionException
- {
- for (Method method : forClass.getMethods())
- {
- addPropertyIfScalaGetterMethod(forClass, descriptors, method);
- }
- }
-
- private void addPropertyIfScalaGetterMethod(Class forClass, List<PropertyDescriptor> descriptors, Method method)
- throws IntrospectionException
- {
- if (!isScalaGetterMethod(method))
- return;
-
- PropertyDescriptor propertyDescriptor = new PropertyDescriptor(method.getName(), forClass, method.getName(),
- null);
-
- // found a getter, looking for the setter now
- try
- {
- Method setterMethod = findScalaSetterMethod(forClass, method);
-
- propertyDescriptor.setWriteMethod(setterMethod);
- }
- catch (NoSuchMethodException e)
- {
- // ignore
- }
-
- // check if the same property was already discovered with java bean accessors
-
- addScalaPropertyIfNoJavaBeansProperty(descriptors, propertyDescriptor, method);
- }
-
- private void addScalaPropertyIfNoJavaBeansProperty(List<PropertyDescriptor> descriptors,
- PropertyDescriptor propertyDescriptor, Method getterMethod)
- {
- boolean found = false;
-
- for (PropertyDescriptor currentPropertyDescriptor : descriptors)
- {
- if (currentPropertyDescriptor.getName().equals(getterMethod.getName()))
- {
- found = true;
-
- break;
- }
- }
-
- if (!found)
- descriptors.add(propertyDescriptor);
- }
-
- private Method findScalaSetterMethod(Class forClass, Method getterMethod) throws NoSuchMethodException
- {
- return forClass.getMethod(getterMethod.getName() + "_$eq", getterMethod.getReturnType());
- }
-
- private boolean isScalaGetterMethod(Method method)
- {
- try
- {
- return Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0
- && !method.getReturnType().equals(Void.TYPE)
- && method.getDeclaringClass().getDeclaredField(method.getName()) != null;
- }
- catch (NoSuchFieldException ex)
- {
- return false;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
deleted file mode 100644
index 97685ef..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2006-2013 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.*;
-import java.util.List;
-
-public class PropertyAdapterImpl implements PropertyAdapter
-{
- private final ClassPropertyAdapter classAdapter;
-
- private final String name;
-
- private final Method readMethod;
-
- private final Method writeMethod;
-
- private final Class type;
-
- private final boolean castRequired;
-
- // Synchronized by this; lazily initialized
- private AnnotationProvider annotationProvider;
-
- private final Field field;
-
- private final Class declaringClass;
-
- PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Method readMethod,
- Method writeMethod)
- {
- this.classAdapter = classAdapter;
- this.name = name;
- this.type = type;
-
- this.readMethod = readMethod;
- this.writeMethod = writeMethod;
-
- declaringClass = readMethod != null ? readMethod.getDeclaringClass() : writeMethod.getDeclaringClass();
-
- castRequired = readMethod != null && readMethod.getReturnType() != type;
-
- field = null;
- }
-
- PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Field field)
- {
- this.classAdapter = classAdapter;
- this.name = name;
- this.type = type;
-
- this.field = field;
-
- declaringClass = field.getDeclaringClass();
-
- castRequired = field.getType() != type;
-
- readMethod = null;
- writeMethod = null;
- }
-
- @Override
- public String getName()
- {
- return name;
- }
-
- @Override
- public Method getReadMethod()
- {
- return readMethod;
- }
-
- @Override
- public Class getType()
- {
- return type;
- }
-
- @Override
- public Method getWriteMethod()
- {
- return writeMethod;
- }
-
- @Override
- public boolean isRead()
- {
- return field != null || readMethod != null;
- }
-
- @Override
- public boolean isUpdate()
- {
- return writeMethod != null || (field != null && !isFinal(field));
- }
-
- private boolean isFinal(Member member)
- {
- return Modifier.isFinal(member.getModifiers());
- }
-
- @Override
- public Object get(Object instance)
- {
- if (field == null && readMethod == null)
- {
- throw new UnsupportedOperationException(String.format("Class %s does not provide an accessor ('getter') method for property '%s'.", toClassName(instance), name));
- }
-
- Throwable fail;
-
- try
- {
- if (field == null)
- return readMethod.invoke(instance);
- else
- return field.get(instance);
- } catch (InvocationTargetException ex)
- {
- fail = ex.getTargetException();
- } catch (Exception ex)
- {
- fail = ex;
- }
-
- throw new RuntimeException(ServiceMessages.readFailure(name, instance, fail), fail);
- }
-
- @Override
- public void set(Object instance, Object value)
- {
- if (field == null && writeMethod == null)
- {
- throw new UnsupportedOperationException(String.format("Class %s does not provide a mutator ('setter') method for property '%s'.",
- toClassName(instance),
- name
- ));
- }
-
- Throwable fail;
-
- try
- {
- if (field == null)
- writeMethod.invoke(instance, value);
- else
- field.set(instance, value);
-
- return;
- } catch (InvocationTargetException ex)
- {
- fail = ex.getTargetException();
- } catch (Exception ex)
- {
- fail = ex;
- }
-
- throw new RuntimeException(String.format("Error updating property '%s' of %s: %s",
- name, toClassName(instance),
- ExceptionUtils.toMessage(fail)), fail);
- }
-
- private String toClassName(Object instance)
- {
- return instance == null ? "<null>" : instance.getClass().getName();
- }
-
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return getAnnnotationProvider().getAnnotation(annotationClass);
- }
-
- /**
- * Creates (as needed) the annotation provider for this property.
- */
- private synchronized AnnotationProvider getAnnnotationProvider()
- {
- if (annotationProvider == null)
- {
- List<AnnotationProvider> providers = CollectionFactory.newList();
-
- if (readMethod != null)
- providers.add(new AccessableObjectAnnotationProvider(readMethod));
-
- if (writeMethod != null)
- providers.add(new AccessableObjectAnnotationProvider(writeMethod));
-
- // There's an assumption here, that the fields match the property name (we ignore case
- // which leads to a manageable ambiguity) and that the field and the getter/setter
- // are in the same class (i.e., that we don't have a getter exposing a protected field inherted
- // from a base class, or some other oddity).
-
- Class cursor = getBeanType();
-
- out:
- while (cursor != null)
- {
- for (Field f : cursor.getDeclaredFields())
- {
- if (f.getName().equalsIgnoreCase(name))
- {
- providers.add(new AccessableObjectAnnotationProvider(f));
-
- break out;
- }
- }
-
- cursor = cursor.getSuperclass();
- }
-
- annotationProvider = AnnotationProviderChain.create(providers);
- }
-
- return annotationProvider;
- }
-
- @Override
- public boolean isCastRequired()
- {
- return castRequired;
- }
-
- @Override
- public ClassPropertyAdapter getClassAdapter()
- {
- return classAdapter;
- }
-
- @Override
- public Class getBeanType()
- {
- return classAdapter.getBeanType();
- }
-
- @Override
- public boolean isField()
- {
- return field != null;
- }
-
- @Override
- public Field getField()
- {
- return field;
- }
-
- @Override
- public Class getDeclaringClass()
- {
- return declaringClass;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
deleted file mode 100644
index e92ef2d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2006, 2007, 2011, 2012 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-public class ServiceMessages
-{
- private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
-
- private ServiceMessages()
- {
- }
-
- public static String noSuchProperty(Class clazz, String propertyName)
- {
- return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
- }
-
-
- public static String readFailure(String propertyName, Object instance, Throwable cause)
- {
- return MESSAGES.format("read-failure", propertyName, instance, cause);
- }
-
- public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
- Class expectedType)
- {
- return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
- expectedType.getName());
- }
-
- public static String shutdownListenerError(Object listener, Throwable cause)
- {
- return MESSAGES.format("shutdown-listener-error", listener, cause);
- }
-
- public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
- {
- return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
- coercion, cause);
- }
-
- public static String registryShutdown(String serviceId)
- {
- return MESSAGES.format("registry-shutdown", serviceId);
- }
-
- public static String serviceBuildFailure(String serviceId, Throwable cause)
- {
- return MESSAGES.format("service-build-failure", serviceId, cause);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
deleted file mode 100644
index 0769b7e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Resource;
-
-/**
- * Implementation of {@link Location} used when the underlying resource isn't really known.
- */
-public final class StringLocation implements Location
-{
- private final String description;
-
- private final int line;
-
- public StringLocation(String description, int line)
- {
- this.description = description;
- this.line = line;
- }
-
- @Override
- public String toString()
- {
- return description;
- }
-
- /**
- * Returns 0.
- */
- @Override
- public int getColumn()
- {
- return 0;
- }
-
- @Override
- public int getLine()
- {
- return line;
- }
-
- /**
- * Returns null; we don't know where the file really is (it's probably a class on the class path).
- */
- @Override
- public Resource getResource()
- {
- return null;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
deleted file mode 100644
index 46f1c0a..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
+++ /dev/null
@@ -1,508 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010, 2012 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.ioc.internal.services;
-
-import org.apache.tapestry5.func.F;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.internal.util.LockSupport;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.services.CoercionTuple;
-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.util.StringToEnumCoercion;
-
-import java.util.*;
-
-@SuppressWarnings("all")
-public class TypeCoercerImpl extends LockSupport implements TypeCoercer
-{
- // Constructed from the service's configuration.
-
- private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
-
- /**
- * A coercion to a specific target type. Manages a cache of coercions to specific types.
- */
- private class TargetCoercion
- {
- private final Class type;
-
- private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
-
- TargetCoercion(Class type)
- {
- this.type = type;
- }
-
- void clearCache()
- {
- cache.clear();
- }
-
- Object coerce(Object input)
- {
- Class sourceType = input != null ? input.getClass() : Void.class;
-
- if (type.isAssignableFrom(sourceType))
- {
- return input;
- }
-
- Coercion c = getCoercion(sourceType);
-
- try
- {
- return type.cast(c.coerce(input));
- } catch (Exception ex)
- {
- throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
- }
- }
-
- String explain(Class sourceType)
- {
- return getCoercion(sourceType).toString();
- }
-
- private Coercion getCoercion(Class sourceType)
- {
- Coercion c = cache.get(sourceType);
-
- if (c == null)
- {
- c = findOrCreateCoercion(sourceType, type);
- cache.put(sourceType, c);
- }
-
- return c;
- }
- }
-
- /**
- * Map from a target type to a TargetCoercion for that type.
- */
- private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
-
- private static final Coercion NO_COERCION = new Coercion<Object, Object>()
- {
- @Override
- public Object coerce(Object input)
- {
- return input;
- }
- };
-
- private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
- {
- @Override
- public Object coerce(Void input)
- {
- return null;
- }
-
- @Override
- public String toString()
- {
- return "null --> null";
- }
- };
-
- public TypeCoercerImpl(Collection<CoercionTuple> tuples)
- {
- for (CoercionTuple tuple : tuples)
- {
- Class key = tuple.getSourceType();
-
- InternalUtils.addToMapList(sourceTypeToTuple, key, tuple);
- }
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Object coerce(Object input, Class targetType)
- {
- assert targetType != null;
-
- Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-
- if (effectiveTargetType.isInstance(input))
- {
- return input;
- }
-
-
- return getTargetCoercion(effectiveTargetType).coerce(input);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
- {
- assert sourceType != null;
- assert targetType != null;
-
- Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
- Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-
- if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
- {
- return NO_COERCION;
- }
-
- return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
- {
- assert sourceType != null;
- assert targetType != null;
-
- Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
- Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
-
- // Is a coercion even necessary? Not if the target type is assignable from the
- // input value.
-
- if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
- {
- return "";
- }
-
- return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
- }
-
- private TargetCoercion getTargetCoercion(Class targetType)
- {
- try
- {
- acquireReadLock();
-
- TargetCoercion tc = typeToTargetCoercion.get(targetType);
-
- return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
- } finally
- {
- releaseReadLock();
- }
- }
-
- private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
- {
- try
- {
- upgradeReadLockToWriteLock();
-
- // Inner check since some other thread may have beat us to it.
-
- TargetCoercion tc = typeToTargetCoercion.get(targetType);
-
- if (tc == null)
- {
- tc = new TargetCoercion(targetType);
- typeToTargetCoercion.put(targetType, tc);
- }
-
- return tc;
- } finally
- {
- downgradeWriteLockToReadLock();
- }
- }
-
- @Override
- public void clearCache()
- {
- try
- {
- acquireReadLock();
-
- // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
- // will release the keys for classes that are no longer in existence. On the other hand,
- // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
- // individual cache, so clear all those.
-
- for (TargetCoercion tc : typeToTargetCoercion.values())
- {
- // Can tc ever be null?
-
- tc.clearCache();
- }
- } finally
- {
- releaseReadLock();
- }
- }
-
- /**
- * Here's the real meat; we do a search of the space to find coercions, or a system of
- * coercions, that accomplish
- * the desired coercion.
- * <p/>
- * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
- * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
- * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
- * <p/>
- * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
- * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
- * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
- * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
- * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
- * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
- * final response.
- * <p/>
- * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
- * really good at.
- *
- * @param sourceType
- * @param targetType
- * @return coercer from sourceType to targetType
- */
- @SuppressWarnings("unchecked")
- private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
- {
- if (sourceType == Void.class)
- {
- return searchForNullCoercion(targetType);
- }
-
- // These are instance variables because this method may be called concurrently.
- // On a true race, we may go to the work of seeking out and/or fabricating
- // a tuple twice, but it's more likely that different threads are looking
- // for different source/target coercions.
-
- Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
- LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
-
- seedQueue(sourceType, targetType, consideredTuples, queue);
-
- while (!queue.isEmpty())
- {
- CoercionTuple tuple = queue.removeFirst();
-
- // If the tuple results in a value type that is assignable to the desired target type,
- // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
- // "quality" (how close is the tuple target type to the desired target type). Cost
- // is currently implicit, as compound tuples are stored deeper in the queue,
- // so simpler coercions will be located earlier.
-
- Class tupleTargetType = tuple.getTargetType();
-
- if (targetType.isAssignableFrom(tupleTargetType))
- {
- return tuple.getCoercion();
- }
-
- // So .. this tuple doesn't get us directly to the target type.
- // However, it *may* get us part of the way. Each of these
- // represents a coercion from the source type to an intermediate type.
- // Now we're going to look for conversions from the intermediate type
- // to some other type.
-
- queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
- }
-
- // Not found anywhere. Identify the source and target type and a (sorted) list of
- // all the known coercions.
-
- throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
- sourceType.getName(), targetType.getName()), buildCoercionCatalog());
- }
-
- /**
- * Coercion from null is special; we match based on the target type and its not a spanning
- * search. In many cases, we
- * return a pass-thru that leaves the value as null.
- *
- * @param targetType
- * desired type
- * @return the coercion
- */
- private Coercion searchForNullCoercion(Class targetType)
- {
- List<CoercionTuple> tuples = getTuples(Void.class, targetType);
-
- for (CoercionTuple tuple : tuples)
- {
- Class tupleTargetType = tuple.getTargetType();
-
- if (targetType.equals(tupleTargetType))
- return tuple.getCoercion();
- }
-
- // Typical case: no match, this coercion passes the null through
- // as null.
-
- return COERCION_NULL_TO_OBJECT;
- }
-
- /**
- * Builds a string listing all the coercions configured for the type coercer, sorted
- * alphabetically.
- */
- @SuppressWarnings("unchecked")
- private AvailableValues buildCoercionCatalog()
- {
- List<CoercionTuple> masterList = CollectionFactory.newList();
-
- for (List<CoercionTuple> list : sourceTypeToTuple.values())
- {
- masterList.addAll(list);
- }
-
- return new AvailableValues("Configured coercions", masterList);
- }
-
- /**
- * Seeds the pool with the initial set of coercions for the given type.
- */
- private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
- LinkedList<CoercionTuple> queue)
- {
- // Work from the source type up looking for tuples
-
- for (Class c : new InheritanceSearch(sourceType))
- {
- List<CoercionTuple> tuples = getTuples(c, targetType);
-
- if (tuples == null)
- {
- continue;
- }
-
- for (CoercionTuple tuple : tuples)
- {
- queue.addLast(tuple);
- consideredTuples.add(tuple);
- }
-
- // Don't pull in Object -> type coercions when doing
- // a search from null.
-
- if (sourceType == Void.class)
- {
- return;
- }
- }
- }
-
- /**
- * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
- * compound coercion tuples
- * to the end of the queue.
- *
- * @param sourceType
- * the source type of the coercion
- * @param targetType
- * TODO
- * @param intermediateTuple
- * a tuple that converts from the source type to some intermediate type (that is not
- * assignable to the target type)
- * @param consideredTuples
- * set of tuples that have already been added to the pool (directly, or as a compound
- * coercion)
- * @param queue
- * the work queue of tuples
- */
- @SuppressWarnings("unchecked")
- private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
- Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
- {
- Class intermediateType = intermediateTuple.getTargetType();
-
- for (Class c : new InheritanceSearch(intermediateType))
- {
- for (CoercionTuple tuple : getTuples(c, targetType))
- {
- if (consideredTuples.contains(tuple))
- {
- continue;
- }
-
- Class newIntermediateType = tuple.getTargetType();
-
- // If this tuple is for coercing from an intermediate type back towards our
- // initial source type, then ignore it. This should only be an optimization,
- // as branches that loop back towards the source type will
- // eventually be considered and discarded.
-
- if (sourceType.isAssignableFrom(newIntermediateType))
- {
- continue;
- }
-
- // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
- // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
- // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
- // intermediate type, hopefully closer to our eventual target type.
-
- Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
-
- CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
-
- // So, every tuple that is added to the queue can take as input the sourceType.
- // The target type may be another intermediate type, or may be something
- // assignable to the target type, which will bring the search to a successful
- // conclusion.
-
- queue.addLast(compoundTuple);
- consideredTuples.add(tuple);
- }
- }
- }
-
- /**
- * Returns a non-null list of the tuples from the source type.
- *
- * @param sourceType
- * used to locate tuples
- * @param targetType
- * used to add synthetic tuples
- * @return non-null list of tuples
- */
- private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
- {
- List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
-
- if (tuples == null)
- {
- tuples = Collections.emptyList();
- }
-
- // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
- // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
- // safe way (i.e., what if the Enum is defined by a class loader that gets discarded? Don't want to cause
- // memory leaks by retaining an instance). In any case, there are edge cases where we may create
- // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
- // configuration), but on the whole, this is cheap and works.
-
- if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
- {
- tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
- }
-
- return tuples;
- }
-
- private static <T> List<T> extend(List<T> list, T extraValue)
- {
- return F.flow(list).append(extraValue).toList();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
deleted file mode 100644
index f1830a7..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2006 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.ioc.internal.util;
-
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Set;
-
-/**
- * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
- * <p/>
- * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
- * skips java.lang.Object.
- * <p/>
- * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
- * interfaces implemented by the initial class at its super classes.
- * <p/>
- * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
- * <p/>
- * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
- * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
- * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
- * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
- * <p/>
- * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
- * search : new InheritanceSearch(startClass)) { ... } </code>
- * <p/>
- * This class is not thread-safe.
- */
-public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
-{
- private Class searchClass;
-
- private final Set<Class> addedInterfaces = CollectionFactory.newSet();
-
- private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
-
- private enum State
- {
- CLASS, INTERFACE, DONE
- }
-
- private State state;
-
- public InheritanceSearch(Class searchClass)
- {
- this.searchClass = searchClass;
-
- queueInterfaces(searchClass);
-
- state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
- }
-
- private void queueInterfaces(Class searchClass)
- {
- for (Class intf : searchClass.getInterfaces())
- {
- if (addedInterfaces.contains(intf)) continue;
-
- interfaceQueue.addLast(intf);
- addedInterfaces.add(intf);
- }
- }
-
- @Override
- public Iterator<Class> iterator()
- {
- return this;
- }
-
- @Override
- public boolean hasNext()
- {
- return state != State.DONE;
- }
-
- @Override
- public Class next()
- {
- switch (state)
- {
- case CLASS:
-
- Class result = searchClass;
-
- searchClass = parentOf(searchClass);
-
- if (searchClass == null) state = State.INTERFACE;
- else queueInterfaces(searchClass);
-
- return result;
-
- case INTERFACE:
-
- if (interfaceQueue.isEmpty())
- {
- state = State.DONE;
- return Object.class;
- }
-
- Class intf = interfaceQueue.removeFirst();
-
- queueInterfaces(intf);
-
- return intf;
-
- default:
- throw new IllegalStateException();
- }
-
- }
-
- /**
- * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
- * Object.class.
- */
- private Class parentOf(Class clazz)
- {
- if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
-
- if (clazz.isArray() && clazz != Object[].class)
- {
- Class componentType = clazz.getComponentType();
-
- while (componentType.isArray()) componentType = componentType.getComponentType();
-
- if (!componentType.isPrimitive()) return Object[].class;
- }
-
- Class parent = clazz.getSuperclass();
-
- return parent != Object.class ? parent : null;
- }
-
- /**
- * @throws UnsupportedOperationException
- * always
- */
- @Override
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
-
-}
[09/15] tapestry-5 git commit: Second pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
Second pass creating the BeanModel and Commons packages.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/c9e97d64
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/c9e97d64
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/c9e97d64
Branch: refs/heads/beanmodel-split
Commit: c9e97d64a51b25c875d5daa94d2f607e4ed299f3
Parents: 1f36bb2
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 16:42:10 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 16:42:10 2014 -0200
----------------------------------------------------------------------
beanmodel/.gitignore | 4 +
beanmodel/build.gradle | 51 ++++-
.../tapestry5/internal/BeanModelUtils.java | 145 +++++++++++++
.../internal/beaneditor/BeanModelImpl.java | 4 +-
.../internal/beaneditor/PropertyModelImpl.java | 14 +-
.../services/PropertyConduitDelegate.java | 1 -
.../services/PropertyConduitSourceImpl.java | 10 +-
.../org/apache/tapestry5/ioc/ObjectLocator.java | 3 +-
.../ioc/internal/util/InternalStringUtils.java | 203 +++++++++++++++++++
.../ioc/internal/util/TapestryException.java | 23 ++-
.../tapestry5/ioc/util/AvailableValues.java | 4 +-
tapestry-core/build.gradle | 37 ----
.../internal/TapestryInternalUtils.java | 46 +----
.../ioc/internal/util/InternalUtils.java | 142 +++----------
14 files changed, 472 insertions(+), 215 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/.gitignore
----------------------------------------------------------------------
diff --git a/beanmodel/.gitignore b/beanmodel/.gitignore
new file mode 100644
index 0000000..f739972
--- /dev/null
+++ b/beanmodel/.gitignore
@@ -0,0 +1,4 @@
+docs
+/.externalToolBuilders
+src/main/generated
+src/test/generated
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
index ccdeb37..c09ebdd 100644
--- a/beanmodel/build.gradle
+++ b/beanmodel/build.gradle
@@ -6,7 +6,18 @@ description = "Fast class property discovery, reading and writing library based
//apply plugin: JavaPlugin
buildDir = 'target/gradle-build'
-
+
+project.ext {
+ antlrSource = "src/main/antlr"
+ mainGeneratedDir = "src/main/generated"
+ testGeneratedDir = "src/test/generated"
+ antlrOutput = "$mainGeneratedDir/antlr"
+}
+
+configurations {
+ antlr3
+}
+
project.ext.libraryVersions = [
jcache: '1.0.0',
]
@@ -15,12 +26,50 @@ dependencies {
compile project(":plastic")
compile project(":tapestry5-annotations")
compile project(":commons")
+
+ // Antlr3 tool path used with the antlr3 task
+ antlr3 "org.antlr:antlr:3.5.2"
+
// 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"
}
}
+// This may spin out as a plugin once we've got the details down pat
+
+task generateGrammarSource(type: JavaExec) {
+ description "Generates Java sources from Antlr3 grammars."
+ inputs.source fileTree(dir: antlrSource, include: "**/*.g")
+ outputs.dir file(antlrOutput)
+
+ classpath configurations.antlr3
+
+ main "org.antlr.Tool"
+ args "-o", "${antlrOutput}/org/apache/tapestry5/internal/antlr"
+ args inputs.sourceFiles
+
+ doFirst {
+ logger.info "Executing Antlr3 grammar generation:\n${commandLine.join(' ')}"
+ }
+}
+
+sourceSets {
+ main {
+ output.dir(antlrOutput, builtBy: generateGrammarSource)
+ java {
+ srcDir antlrOutput
+ }
+ }
+}
+
+clean.delete mainGeneratedDir, testGeneratedDir
+
+compileJava {
+ dependsOn generateGrammarSource
+ options.fork(memoryMaximumSize: '512m')
+}
+
jar {
manifest {
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
new file mode 100644
index 0000000..08cb88a
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
@@ -0,0 +1,145 @@
+// 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.internal;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+
+/**
+ * Some methods broken off tapestry-core's InternalUtils to avoid bringing the whole class
+ * plus its multiple dependencies to the BeanModel package.
+ */
+public class BeanModelUtils {
+
+ public static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+ /**
+ * @since 5.3
+ */
+ private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
+
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/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
index 26eb309..b72a3d6 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
@@ -22,7 +22,7 @@ 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.internal.util.InternalStringUtils;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.UnknownValueException;
@@ -93,7 +93,7 @@ public class BeanModelImpl<T> implements BeanModel<T>
private void validateNewPropertyName(String propertyName)
{
- assert InternalUtils.isNonBlank(propertyName);
+ assert InternalStringUtils.isNonBlank(propertyName);
if (properties.containsKey(propertyName))
throw new RuntimeException(String.format(
"Bean editor model for %s already contains a property model for property '%s'.",
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/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
index 703ce44..b21e5bb 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -14,17 +14,17 @@
package org.apache.tapestry5.internal.beaneditor;
+import java.lang.annotation.Annotation;
+
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.internal.BeanModelUtils;
import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
-import java.lang.annotation.Annotation;
-
@SuppressWarnings("all")
public class PropertyModelImpl implements PropertyModel
{
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
this.name = name;
this.conduit = conduit;
- id = TapestryInternalUtils.extractIdFromPropertyExpression(name);
+ id = BeanModelUtils.extractIdFromPropertyExpression(name);
- label = TapestryInternalUtils.defaultLabel(id, messages, name);
+ label = BeanModelUtils.defaultLabel(id, messages, name);
// TAP5-2305
if (conduit != null)
@@ -87,7 +87,7 @@ public class PropertyModelImpl implements PropertyModel
public PropertyModel label(String label)
{
- assert InternalUtils.isNonBlank(label);
+ assert InternalStringUtils.isNonBlank(label);
this.label = label;
return this;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/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
index 1242031..3849103 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
@@ -19,7 +19,6 @@ 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;
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 701420f..83f67fa 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -19,6 +19,7 @@ import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.Tree;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.PropertyConduit2;
+import org.apache.tapestry5.internal.BeanModelUtils;
import org.apache.tapestry5.internal.InternalPropertyConduit;
import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -29,7 +30,7 @@ import org.apache.tapestry5.ioc.annotations.PostInjection;
import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
import org.apache.tapestry5.ioc.services.*;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.ExceptionUtils;
@@ -1106,7 +1107,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
- InternalUtils.joinSorted(tokenNames));
+ InternalStringUtils.joinSorted(tokenNames));
return new RuntimeException(message);
}
@@ -1259,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
Type returnType = GenericsUtils.extractActualType(activeType, method);
- return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+ return new Term(returnType, toUniqueId(method), BeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
{
@@ -1363,7 +1364,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
public PropertyConduit create(Class rootClass, String expression)
{
assert rootClass != null;
- assert InternalUtils.isNonBlank(expression);
+ assert InternalStringUtils.isNonBlank(expression);
MultiKey key = new MultiKey(rootClass, expression);
@@ -1560,4 +1561,5 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
return builder.append(")").toString();
}
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
index 81d1f77..e60c0d9 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2010, 2011 The Apache Software Foundation
+// Copyright 2006, 2007, 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.
@@ -15,7 +15,6 @@
package org.apache.tapestry5.ioc;
import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.services.MasterObjectProvider;
import java.lang.annotation.Annotation;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
new file mode 100644
index 0000000..e345593
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
@@ -0,0 +1,203 @@
+// Copyright 2006-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.ioc.internal.util;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
+ * Broken off Tapestry-IoC's InternalUtils.
+ */
+@SuppressWarnings("all")
+public class InternalStringUtils
+{
+
+ /**
+ * Pattern used to eliminate leading and trailing underscores and dollar signs.
+ */
+ private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+ * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+ *
+ * @param method
+ * @return short string representation
+ */
+ public static String asString(Method method)
+ {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append(method.getDeclaringClass().getName());
+ buffer.append(".");
+ buffer.append(method.getName());
+ buffer.append("(");
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ if (i > 0)
+ buffer.append(", ");
+
+ String name = method.getParameterTypes()[i].getSimpleName();
+
+ buffer.append(name);
+ }
+
+ return buffer.append(")").toString();
+ }
+
+ /**
+ * Strips leading "_" and "$" and trailing "_" from the name.
+ */
+ public static String stripMemberName(String memberName)
+ {
+ assert isNonBlank(memberName);
+ Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+ if (!matcher.matches())
+ throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+ return matcher.group(1);
+ }
+
+ /**
+ * Joins together some number of elements to form a comma separated list.
+ */
+ public static String join(List elements)
+ {
+ return join(elements, ", ");
+ }
+
+ /**
+ * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+ * string "(blank)".
+ *
+ * @param elements
+ * objects to be joined together
+ * @param separator
+ * used between elements when joining
+ */
+ public static String join(List elements, String separator)
+ {
+ switch (elements.size())
+ {
+ case 0:
+ return "";
+
+ case 1:
+ return elements.get(0).toString();
+
+ default:
+
+ StringBuilder buffer = new StringBuilder();
+ boolean first = true;
+
+ for (Object o : elements)
+ {
+ if (!first)
+ buffer.append(separator);
+
+ String string = String.valueOf(o);
+
+ if (string.equals(""))
+ string = "(blank)";
+
+ buffer.append(string);
+
+ first = false;
+ }
+
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+ *
+ * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+ * empty
+ */
+ public static String joinSorted(Collection elements)
+ {
+ if (elements == null || elements.isEmpty())
+ return "(none)";
+
+ List<String> list = CollectionFactory.newList();
+
+ for (Object o : elements)
+ list.add(String.valueOf(o));
+
+ Collections.sort(list);
+
+ return join(list);
+ }
+
+ /**
+ * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ */
+
+ public static boolean isBlank(String input)
+ {
+ return input == null || input.length() == 0 || input.trim().length() == 0;
+ }
+
+ public static boolean isNonBlank(String input)
+ {
+ return !isBlank(input);
+ }
+
+ /**
+ * Capitalizes a string, converting the first character to uppercase.
+ */
+ public static String capitalize(String input)
+ {
+ if (input.length() == 0)
+ return input;
+
+ return input.substring(0, 1).toUpperCase() + input.substring(1);
+ }
+
+ /**
+ * Return true if the input string contains the marker for symbols that must be expanded.
+ */
+ public static boolean containsSymbols(String input)
+ {
+ return input.contains("${");
+ }
+
+ /**
+ * Searches the string for the final period ('.') character and returns everything after that. The input string is
+ * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+ * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+ * character.
+ */
+ public static String lastTerm(String input)
+ {
+ assert isNonBlank(input);
+ int dotx = input.lastIndexOf('.');
+
+ if (dotx < 0)
+ return input;
+
+ return input.substring(dotx + 1);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index ef217cb..d8d8018 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
*/
public TapestryException(String message, Object location, Throwable cause)
{
- this(message, InternalUtils.locationOf(location), cause);
+ this(message, locationOf(location), cause);
}
/**
@@ -71,5 +71,26 @@ public class TapestryException extends RuntimeException implements Locatable
return String.format("%s [at %s]", super.toString(), location);
}
+
+ /**
+ * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+ * convertable to a location.
+ * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
+ */
+
+ private static Location locationOf(Object location)
+ {
+ if (location == null)
+ return null;
+
+ if (location instanceof Location)
+ return (Location) location;
+
+ if (location instanceof Locatable)
+ return ((Locatable) location).getLocation();
+
+ return null;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index c4c5c6d..8c9cb3f 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
import java.util.Map;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
/**
* Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
@Override
public String toString()
{
- return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
+ return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-core/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index 584200a..d35c166 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -8,11 +8,6 @@ project.ext {
antlrSource = "src/main/antlr"
mainGeneratedDir = "src/main/generated"
testGeneratedDir = "src/test/generated"
- antlrOutput = "$mainGeneratedDir/antlr"
-}
-
-configurations {
- antlr3
}
dependencies {
@@ -27,30 +22,9 @@ dependencies {
compile "commons-codec:commons-codec:1.5"
- // Antlr3 tool path used with the antlr3 task
- antlr3 "org.antlr:antlr:3.5.2"
-
testRuntime "org.hsqldb:hsqldb:1.8.0.10"
}
-// This may spin out as a plugin once we've got the details down pat
-
-task generateGrammarSource(type: JavaExec) {
- description "Generates Java sources from Antlr3 grammars."
- inputs.source fileTree(dir: antlrSource, include: "**/*.g")
- outputs.dir file(antlrOutput)
-
- classpath configurations.antlr3
-
- main "org.antlr.Tool"
- args "-o", "${antlrOutput}/org/apache/tapestry5/internal/antlr"
- args inputs.sourceFiles
-
- doFirst {
- logger.info "Executing Antlr3 grammar generation:\n${commandLine.join(' ')}"
- }
-}
-
task preprocessCoffeeScript(type: PreprocessCoffeeScript) {
}
@@ -73,23 +47,12 @@ sourceSets {
main {
output.dir(compileCoffeeScript.outputDir, builtBy: compileCoffeeScript)
output.dir(compileProcessedCoffeescript.outputDir, builtBy: compileProcessedCoffeescript)
- output.dir(antlrOutput, builtBy: generateGrammarSource)
- java {
- srcDir antlrOutput
- }
}
test {
output.dir(compileTestCoffeeScript.outputDir, builtBy: compileTestCoffeeScript)
}
}
-clean.delete mainGeneratedDir, testGeneratedDir
-
-compileJava {
- dependsOn generateGrammarSource
- options.fork(memoryMaximumSize: '512m')
-}
-
// Not sure why this is necessary:
compileTestGroovy.dependsOn compileTestJava
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index 3435d64..aba7225 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,40 +59,7 @@ public class TapestryInternalUtils
*/
public static String toUserPresentable(String id)
{
- StringBuilder builder = new StringBuilder(id.length() * 2);
-
- char[] chars = id.toCharArray();
- boolean postSpace = true;
- boolean upcaseNext = true;
-
- for (char ch : chars)
- {
- if (upcaseNext)
- {
- builder.append(Character.toUpperCase(ch));
- upcaseNext = false;
-
- continue;
- }
-
- if (ch == '_')
- {
- builder.append(' ');
- upcaseNext = true;
- continue;
- }
-
- boolean upperCase = Character.isUpperCase(ch);
-
- if (upperCase && !postSpace)
- builder.append(' ');
-
- builder.append(ch);
-
- postSpace = upperCase;
- }
-
- return builder.toString();
+ return BeanModelUtils.toUserPresentable(id);
}
public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -261,7 +228,7 @@ public class TapestryInternalUtils
*/
public static String extractIdFromPropertyExpression(String expression)
{
- return replace(expression, NON_WORD_PATTERN, "");
+ return BeanModelUtils.extractIdFromPropertyExpression(expression);
}
/**
@@ -270,12 +237,7 @@ public class TapestryInternalUtils
*/
public static String defaultLabel(String id, Messages messages, String propertyExpression)
{
- String key = id + "-label";
-
- if (messages.contains(key))
- return messages.get(key);
-
- return toUserPresentable(extractIdFromPropertyExpression(lastTerm(propertyExpression)));
+ return BeanModelUtils.defaultLabel(id, messages, propertyExpression);
}
/**
@@ -342,7 +304,7 @@ public class TapestryInternalUtils
private static String replace(String input, Pattern pattern, String replacement)
{
- return pattern.matcher(input).replaceAll(replacement);
+ return BeanModelUtils.replace(input, pattern, replacement);
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c9e97d64/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index e9e7806..a40f984 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,16 +17,16 @@ package org.apache.tapestry5.ioc.internal.util;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.func.Mapper;
import org.apache.tapestry5.func.Predicate;
+import org.apache.tapestry5.internal.BeanModelUtils;
import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
import org.apache.tapestry5.ioc.def.*;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
import org.apache.tapestry5.ioc.internal.ServiceDefImpl;
import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
import org.apache.tapestry5.ioc.util.ExceptionUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
import org.slf4j.Logger;
import javax.annotation.PostConstruct;
@@ -56,18 +56,6 @@ public class InternalUtils
public static final boolean SERVICE_CLASS_RELOADING_ENABLED = Boolean.parseBoolean(System.getProperty(
IOCConstants.SERVICE_CLASS_RELOADING_ENABLED, "true"));
-
- /**
- * Pattern used to eliminate leading and trailing underscores and dollar signs.
- */
- private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
- Pattern.CASE_INSENSITIVE);
-
- /**
- * @since 5.3
- */
- public static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-
/**
* Converts a method to a user presentable string using a {@link PlasticProxyFactory} to obtain a {@link Location}
* (where possible). {@link #asString(Method)} is used under the covers, to present a detailed, but not excessive,
@@ -92,27 +80,11 @@ public class InternalUtils
*
* @param method
* @return short string representation
+ * @deprecated use {@link InternalStringUtils#asString(Method)} instead.
*/
public static String asString(Method method)
{
- StringBuilder buffer = new StringBuilder();
-
- buffer.append(method.getDeclaringClass().getName());
- buffer.append(".");
- buffer.append(method.getName());
- buffer.append("(");
-
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- if (i > 0)
- buffer.append(", ");
-
- String name = method.getParameterTypes()[i].getSimpleName();
-
- buffer.append(name);
- }
-
- return buffer.append(")").toString();
+ return InternalStringUtils.asString(method);
}
/**
@@ -131,16 +103,11 @@ public class InternalUtils
/**
* Strips leading "_" and "$" and trailing "_" from the name.
+ * @deprecated use {@link InternalStringUtils#stripMemberName(String)} instead.
*/
public static String stripMemberName(String memberName)
{
- assert InternalUtils.isNonBlank(memberName);
- Matcher matcher = NAME_PATTERN.matcher(memberName);
-
- if (!matcher.matches())
- throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
- return matcher.group(1);
+ return InternalStringUtils.stripMemberName(memberName);
}
/**
@@ -425,10 +392,11 @@ public class InternalUtils
/**
* Joins together some number of elements to form a comma separated list.
+ * @deprecated use {@link InternalStringUtils#join(List)} instead.
*/
public static String join(List elements)
{
- return join(elements, ", ");
+ return InternalStringUtils.join(elements);
}
/**
@@ -439,39 +407,11 @@ public class InternalUtils
* objects to be joined together
* @param separator
* used between elements when joining
+ * @deprecated use {@link InternalStringUtils#asString(Method, String)} instead.
*/
public static String join(List elements, String separator)
{
- switch (elements.size())
- {
- case 0:
- return "";
-
- case 1:
- return elements.get(0).toString();
-
- default:
-
- StringBuilder buffer = new StringBuilder();
- boolean first = true;
-
- for (Object o : elements)
- {
- if (!first)
- buffer.append(separator);
-
- String string = String.valueOf(o);
-
- if (string.equals(""))
- string = "(blank)";
-
- buffer.append(string);
-
- first = false;
- }
-
- return buffer.toString();
- }
+ return InternalStringUtils.join(elements, separator);
}
/**
@@ -479,29 +419,21 @@ public class InternalUtils
*
* @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
* empty
+ * @deprecated use {@link InternalStringUtils#joinSorted(Collection)} instead.
*/
public static String joinSorted(Collection elements)
{
- if (elements == null || elements.isEmpty())
- return "(none)";
-
- List<String> list = CollectionFactory.newList();
-
- for (Object o : elements)
- list.add(String.valueOf(o));
-
- Collections.sort(list);
-
- return join(list);
+ return InternalStringUtils.joinSorted(elements);
}
/**
* Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ * @deprecated use {@link InternalStringUtils#isBlank(String)} instead.
*/
public static boolean isBlank(String input)
{
- return input == null || input.length() == 0 || input.trim().length() == 0;
+ return InternalStringUtils.isBlank(input);
}
/**
@@ -518,20 +450,21 @@ public class InternalUtils
return false;
}
+ /**
+ * @deprecated use {@link InternalStringUtils#isNonBlank(String)} instead.
+ */
public static boolean isNonBlank(String input)
{
- return !isBlank(input);
+ return InternalStringUtils.isNonBlank(input);
}
/**
* Capitalizes a string, converting the first character to uppercase.
+ * @deprecated use {@link InternalStringUtils#capitalize(String)} instead.
*/
public static String capitalize(String input)
{
- if (input.length() == 0)
- return input;
-
- return input.substring(0, 1).toUpperCase() + input.substring(1);
+ return InternalStringUtils.capitalize(input);
}
/**
@@ -639,10 +572,11 @@ public class InternalUtils
/**
* Return true if the input string contains the marker for symbols that must be expanded.
+ * @deprecated use {@link InternalStringUtils#containsSymbols(String)} instead.
*/
public static boolean containsSymbols(String input)
{
- return input.contains("${");
+ return InternalStringUtils.containsSymbols(input);
}
/**
@@ -650,16 +584,11 @@ public class InternalUtils
* generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
* expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
* character.
+ * @deprecated use {@link InternalStringUtils#lastTerm(String)} instead.
*/
public static String lastTerm(String input)
{
- assert InternalUtils.isNonBlank(input);
- int dotx = input.lastIndexOf('.');
-
- if (dotx < 0)
- return input;
-
- return input.substring(dotx + 1);
+ return InternalStringUtils.lastTerm(input);
}
/**
@@ -848,18 +777,9 @@ public class InternalUtils
*/
public static AnnotationProvider toAnnotationProvider(final Class element)
{
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationClass.cast(element.getAnnotation(annotationClass));
- }
- };
+ return BeanModelUtils.toAnnotationProvider(element);
}
- ;
-
/**
* @since 5.3
*/
@@ -1484,17 +1404,7 @@ public class InternalUtils
public static AnnotationProvider toAnnotationProvider(final Method element)
{
- if (element == null)
- return NULL_ANNOTATION_PROVIDER;
-
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return element.getAnnotation(annotationClass);
- }
- };
+ return BeanModelUtils.toAnnotationProvider(element);
}
public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,
[04/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
new file mode 100644
index 0000000..b9b4aa3
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
@@ -0,0 +1,33 @@
+// Copyright 2006, 2007, 2012 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.services;
+
+/**
+ * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files,
+ * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external
+ * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as
+ * necessary).
+ *
+ * @see org.apache.tapestry5.services.InvalidationEventHub
+ * @since 5.1.0.0
+ * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead
+ */
+public interface InvalidationListener
+{
+ /**
+ * Invoked to indicate that some object is invalid. The receiver should clear its cache.
+ */
+ void objectWasInvalidated();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index 6397777..593c3a4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -4,5 +4,5 @@ include "tapestry-beanvalidator", "tapestry-jpa", "tapestry-kaptcha"
include "tapestry-javadoc", "quickstart", "tapestry-clojure", "tapestry-mongodb"
include "tapestry-test-data", 'tapestry-internal-test', "tapestry-ioc-junit"
include "tapestry-webresources", "tapestry-runner", "tapestry-test-constants"
-include "tapestry-ioc-jcache"
+include "tapestry-ioc-jcache", "beanmodel", "commons"
// include "tapestry-cdi"
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-core/build.gradle b/tapestry-core/build.gradle
index c16cd48..584200a 100644
--- a/tapestry-core/build.gradle
+++ b/tapestry-core/build.gradle
@@ -18,6 +18,7 @@ configurations {
dependencies {
compile project(':tapestry-ioc')
compile project(':tapestry-json')
+ compile project(':beanmodel')
provided project(":tapestry-test")
provided project(":tapestry-test-constants")
@@ -26,11 +27,6 @@ dependencies {
compile "commons-codec:commons-codec:1.5"
- // 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"
- }
-
// Antlr3 tool path used with the antlr3 task
antlr3 "org.antlr:antlr:3.5.2"
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
deleted file mode 100644
index 3dbb0c0..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java b/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
deleted file mode 100644
index 839d70f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/PropertyConduit2.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java b/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
deleted file mode 100644
index 0a60fd7..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/BeanModel.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java b/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
deleted file mode 100644
index 6095fb9..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/beaneditor/PropertyModel.java
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
deleted file mode 100644
index 315b372..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalPropertyConduit.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
deleted file mode 100644
index 26eb309..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ /dev/null
@@ -1,289 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
deleted file mode 100644
index 703ce44..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
deleted file mode 100644
index 4dbfb2d..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/CoercingPropertyConduitWrapper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
deleted file mode 100644
index 1242031..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitDelegate.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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);
- }
-}
[03/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
deleted file mode 100644
index 701420f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ /dev/null
@@ -1,1563 +0,0 @@
-// Copyright 2007-2013 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 org.antlr.runtime.ANTLRInputStream;
-import org.antlr.runtime.CommonTokenStream;
-import org.antlr.runtime.tree.Tree;
-import org.apache.tapestry5.PropertyConduit;
-import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.internal.InternalPropertyConduit;
-import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
-import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
-import org.apache.tapestry5.internal.util.IntegerRange;
-import org.apache.tapestry5.internal.util.MultiKey;
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.annotations.PostInjection;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.ioc.util.AvailableValues;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-import org.apache.tapestry5.ioc.util.UnknownValueException;
-import org.apache.tapestry5.plastic.*;
-import org.apache.tapestry5.services.ComponentClasses;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.InvalidationEventHub;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
-
-public class PropertyConduitSourceImpl implements PropertyConduitSource
-{
- static class ConduitMethods
- {
- private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
-
- private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
- Object.class);
-
- private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
- "getPropertyType");
-
- private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class,
- "getPropertyGenericType");
-
- private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
- "getPropertyName");
-
- private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
- "getAnnotation", Class.class);
-
- }
-
- static class DelegateMethods
- {
- static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
-
- static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
-
- static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class);
- }
-
- static class ArrayListMethods
- {
- static final Method ADD = getMethod(ArrayList.class, "add", Object.class);
- }
-
- static class HashMapMethods
- {
- static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class);
- }
-
- private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadNull().returnResult();
- }
- };
-
- private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
- {Object.class.getName()};
-
- @SuppressWarnings("unchecked")
- private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
- {
- try
- {
- return containingClass.getMethod(name, parameterTypes);
- } catch (NoSuchMethodException ex)
- {
- throw new IllegalArgumentException(ex);
- }
- }
-
- private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
- {
- return new MethodDescription(getMethod(containingClass, name, parameterTypes));
- }
-
- private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
-
- /**
- * How are null values in intermdiate terms to be handled?
- */
- private enum NullHandling
- {
- /**
- * Add code to check for null and throw exception if null.
- */
- FORBID,
-
- /**
- * Add code to check for null and short-circuit (i.e., the "?."
- * safe-dereference operator)
- */
- ALLOW
- }
-
- /**
- * One term in an expression. Expressions start with some root type and each term advances
- * to a new type.
- */
- private class Term
- {
- /**
- * The generic type of the term.
- */
- final Type type;
-
- final Class genericType;
-
- /**
- * Describes the term, for use in error messages.
- */
- final String description;
-
- final AnnotationProvider annotationProvider;
-
- /**
- * Callback that will implement the term.
- */
- final InstructionBuilderCallback callback;
-
- Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
- InstructionBuilderCallback callback)
- {
- this.type = type;
- this.genericType = genericType;
- this.description = description;
- this.annotationProvider = annotationProvider;
- this.callback = callback;
- }
-
- Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback)
- {
- this(type, GenericsUtils.asClass(type), description, annotationProvider, callback);
- }
-
- Term(Type type, String description, InstructionBuilderCallback callback)
- {
- this(type, description, null, callback);
- }
-
- /**
- * Returns a clone of this Term with a new callback.
- */
- Term withCallback(InstructionBuilderCallback newCallback)
- {
- return new Term(type, genericType, description, annotationProvider, newCallback);
- }
- }
-
- private final PropertyAccess access;
-
- private final PlasticProxyFactory proxyFactory;
-
- private final TypeCoercer typeCoercer;
-
- private final StringInterner interner;
-
- /**
- * Keyed on combination of root class and expression.
- */
- private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap();
-
- private final Invariant invariantAnnotation = new Invariant()
- {
- public Class<? extends Annotation> annotationType()
- {
- return Invariant.class;
- }
- };
-
- private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider()
- {
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- if (annotationClass == Invariant.class)
- return annotationClass.cast(invariantAnnotation);
-
- return null;
- }
- };
-
- private final PropertyConduit literalTrue;
-
- private final PropertyConduit literalFalse;
-
- private final PropertyConduit literalNull;
-
- private final PropertyConduitDelegate sharedDelegate;
-
- /**
- * Encapsulates the process of building a PropertyConduit instance from an
- * expression, as an {@link PlasticClassTransformer}.
- */
- class PropertyConduitBuilder implements PlasticClassTransformer
- {
- private final Class rootType;
-
- private final String expression;
-
- private final Tree tree;
-
- private Class conduitPropertyType;
-
- private Type conduitPropertyGenericType;
-
- private String conduitPropertyName;
-
- private AnnotationProvider annotationProvider = nullAnnotationProvider;
-
- private PlasticField delegateField;
-
- private PlasticClass plasticClass;
-
- private PlasticMethod getRootMethod, navMethod;
-
- PropertyConduitBuilder(Class rootType, String expression, Tree tree)
- {
- this.rootType = rootType;
- this.expression = expression;
- this.tree = tree;
- }
-
- public void transform(PlasticClass plasticClass)
- {
- this.plasticClass = plasticClass;
-
- // Create the various methods; also determine the conduit's property type, property name and identify
- // the annotation provider.
-
- implementNavMethodAndAccessors();
-
- implementOtherMethods();
-
- plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
- }
-
- private void implementOtherMethods()
- {
- PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class,
- "annotationProvider").inject(annotationProvider);
-
- plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField);
-
- plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadConstant(conduitPropertyName).returnResult();
- }
- });
-
- final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject(
- conduitPropertyType);
-
- plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadThis().getField(propertyTypeField).returnResult();
- }
- });
-
- final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject(
- conduitPropertyGenericType);
-
- plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadThis().getField(propertyGenericTypeField).returnResult();
- }
- });
- }
-
- /**
- * Creates a method that does a conversion from Object to the expected root type, with
- * a null check.
- */
- private void implementGetRoot()
- {
- getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
- SINGLE_OBJECT_ARGUMENT, null);
-
- getRootMethod.changeImplementation(new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.throwException(NullPointerException.class,
- String.format("Root object of property expression '%s' is null.", expression));
- }
- });
-
- builder.checkcast(rootType).returnResult();
- }
- });
- }
-
- private boolean isLeaf(Tree node)
- {
- int type = node.getType();
-
- return type != DEREF && type != SAFEDEREF;
- }
-
- private void implementNavMethodAndAccessors()
- {
- implementGetRoot();
-
- // First, create the navigate method.
-
- final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
-
- Type activeType = rootType;
-
- Tree node = tree;
-
- while (!isLeaf(node))
- {
- Term term = analyzeDerefNode(activeType, node);
-
- callbacks.add(term.callback);
-
- activeType = term.type;
-
- // Second term is the continuation, possibly another chained
- // DEREF, etc.
- node = node.getChild(1);
- }
-
- Class activeClass = GenericsUtils.asClass(activeType);
-
- if (callbacks.isEmpty())
- {
- navMethod = getRootMethod;
- } else
- {
- navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
- SINGLE_OBJECT_ARGUMENT, null);
-
- navMethod.changeImplementation(new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
-
- for (InstructionBuilderCallback callback : callbacks)
- {
- callback.doBuild(builder);
- }
-
- builder.returnResult();
- }
- });
- }
-
- implementAccessors(activeType, node);
- }
-
- private void implementAccessors(Type activeType, Tree node)
- {
- switch (node.getType())
- {
- case IDENTIFIER:
-
- implementPropertyAccessors(activeType, node);
-
- return;
-
- case INVOKE:
-
- // So, at this point, we have the navigation method written
- // and it covers all but the terminal
- // de-reference. node is an IDENTIFIER or INVOKE. We're
- // ready to use the navigation
- // method to implement get() and set().
-
- implementMethodAccessors(activeType, node);
-
- return;
-
- case RANGEOP:
-
- // As currently implemented, RANGEOP can only appear as the
- // top level, which
- // means we didn't need the navigate method after all.
-
- implementRangeOpGetter(node);
- implementNoOpSetter();
-
- conduitPropertyType = IntegerRange.class;
- conduitPropertyGenericType = IntegerRange.class;
-
- return;
-
- case LIST:
-
- implementListGetter(node);
- implementNoOpSetter();
-
- conduitPropertyType = List.class;
- conduitPropertyGenericType = List.class;
-
- return;
-
- case MAP:
- implementMapGetter(node);
- implementNoOpSetter();
-
- conduitPropertyType = Map.class;
- conduitPropertyGenericType = Map.class;
-
- return;
-
-
- case NOT:
- implementNotOpGetter(node);
- implementNoOpSetter();
-
- conduitPropertyType = boolean.class;
- conduitPropertyGenericType = boolean.class;
-
- return;
-
- default:
- throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
- }
- }
-
- public void implementMethodAccessors(final Type activeType, final Tree invokeNode)
- {
- final Term term = buildInvokeTerm(activeType, invokeNode);
-
- implementNoOpSetter();
-
- conduitPropertyName = term.description;
- conduitPropertyType = term.genericType;
- conduitPropertyGenericType = term.genericType;
- annotationProvider = term.annotationProvider;
-
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- term.callback.doBuild(builder);
-
- boxIfPrimitive(builder, conduitPropertyType);
-
- builder.returnResult();
- }
- });
-
- implementNoOpSetter();
- }
-
- public void implementPropertyAccessors(Type activeType, Tree identifierNode)
- {
- String propertyName = identifierNode.getText();
-
- PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
-
- conduitPropertyName = propertyName;
- conduitPropertyType = adapter.getType();
- conduitPropertyGenericType = getGenericType(adapter);
- annotationProvider = adapter;
-
- implementGetter(adapter);
- implementSetter(adapter);
- }
-
- private Type getGenericType(PropertyAdapter adapter)
- {
- Type genericType = null;
- if (adapter.getField() != null)
- {
- genericType = adapter.getField().getGenericType();
- }
- else if (adapter.getReadMethod() != null)
- {
- genericType = adapter.getReadMethod().getGenericReturnType();
- }
- else if (adapter.getWriteMethod() != null)
- {
- genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
- }
- else
- {
- throw new RuntimeException("Could not find accessor for property " + adapter.getName());
- }
-
- return genericType == null ? adapter.getType() : genericType;
- }
-
- private void implementSetter(PropertyAdapter adapter)
- {
- if (adapter.getWriteMethod() != null)
- {
- implementSetter(adapter.getWriteMethod());
- return;
- }
-
- if (adapter.getField() != null && adapter.isUpdate())
- {
- implementSetter(adapter.getField());
- return;
- }
-
- implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
- rootType.getName());
- }
-
- private boolean isStatic(Member member)
- {
- return Modifier.isStatic(member.getModifiers());
- }
-
- private void implementSetter(final Field field)
- {
- if (isStatic(field))
- {
- plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
-
- builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
- builder.returnResult();
- }
- });
-
- return;
- }
-
- plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
-
- builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
- builder.returnResult();
- }
- });
- }
-
- private void implementSetter(final Method writeMethod)
- {
- plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- Class propertyType = writeMethod.getParameterTypes()[0];
- String propertyTypeName = PlasticUtils.toTypeName(propertyType);
-
- builder.loadArgument(1).castOrUnbox(propertyTypeName);
-
- builder.invoke(writeMethod);
-
- builder.returnResult();
- }
- });
- }
-
- private void implementGetter(PropertyAdapter adapter)
- {
- if (adapter.getReadMethod() != null)
- {
- implementGetter(adapter.getReadMethod());
- return;
- }
-
- if (adapter.getField() != null)
- {
- implementGetter(adapter.getField());
- return;
- }
-
- implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression,
- rootType.getName());
- }
-
- private void implementGetter(final Field field)
- {
- if (isStatic(field))
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
- // Cast not necessary here since the return type of get() is Object
-
- boxIfPrimitive(builder, field.getType());
-
- builder.returnResult();
- }
- });
-
- return;
- }
-
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType());
-
- // Cast not necessary here since the return type of get() is Object
-
- boxIfPrimitive(builder, field.getType());
-
- builder.returnResult();
- }
- });
- }
-
- private void implementGetter(final Method readMethod)
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeNavigateMethod(builder);
-
- invokeMethod(builder, readMethod, null, 0);
-
- boxIfPrimitive(builder, conduitPropertyType);
-
- builder.returnResult();
- }
- });
- }
-
- private void implementRangeOpGetter(final Tree rangeNode)
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- // Put the delegate on top of the stack
-
- builder.loadThis().getField(getDelegateField());
-
- invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0);
-
- builder.returnResult();
- }
- });
- }
-
- /**
- * @param node
- * subexpression to invert
- */
- private void implementNotOpGetter(final Tree node)
- {
- // Implement get() as navigate, then do a method invocation based on node
- // then, then pass (wrapped) result to delegate.invert()
-
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- Type expressionType = implementNotExpression(builder, node);
-
- // Yes, we know this will always be the case, for now.
-
- boxIfPrimitive(builder, expressionType);
-
- builder.returnResult();
- }
- });
- }
-
- /**
- * The first part of any implementation of get() or set(): invoke the navigation method
- * and if the result is null, return immediately.
- */
- private void invokeNavigateMethod(InstructionBuilder builder)
- {
- builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
-
- builder.dupe().when(Condition.NULL, RETURN_NULL);
- }
-
- /**
- * Uses the builder to add instructions for a subexpression.
- *
- * @param builder
- * used to add instructions
- * @param activeType
- * type of value on top of the stack when this code will execute, or null if no value on stack
- * @param node
- * defines the expression
- * @return the expression type
- */
- private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
- {
- Term term;
-
- while (true)
- {
- switch (node.getType())
- {
- case IDENTIFIER:
- case INVOKE:
-
- if (activeType == null)
- {
- invokeGetRootMethod(builder);
-
- activeType = rootType;
- }
-
- term = buildTerm(activeType, node);
-
- term.callback.doBuild(builder);
-
- return term.type;
-
- case INTEGER:
-
- builder.loadConstant(new Long(node.getText()));
-
- return long.class;
-
- case DECIMAL:
-
- builder.loadConstant(new Double(node.getText()));
-
- return double.class;
-
- case STRING:
-
- builder.loadConstant(node.getText());
-
- return String.class;
-
- case DEREF:
- case SAFEDEREF:
-
- if (activeType == null)
- {
- invokeGetRootMethod(builder);
-
- activeType = rootType;
- }
-
- term = analyzeDerefNode(activeType, node);
-
- term.callback.doBuild(builder);
-
- activeType = GenericsUtils.asClass(term.type);
-
- node = node.getChild(1);
-
- break;
-
- case TRUE:
- case FALSE:
-
- builder.loadConstant(node.getType() == TRUE ? 1 : 0);
-
- return boolean.class;
-
- case LIST:
-
- return implementListConstructor(builder, node);
-
- case MAP:
- return implementMapConstructor(builder, node);
-
- case NOT:
-
- return implementNotExpression(builder, node);
-
- case THIS:
-
- invokeGetRootMethod(builder);
-
- return rootType;
-
- case NULL:
-
- builder.loadNull();
-
- return Void.class;
-
- default:
- throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
- IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
- }
- }
- }
-
- public void invokeGetRootMethod(InstructionBuilder builder)
- {
- builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
- }
-
- private void implementListGetter(final Tree listNode)
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- implementListConstructor(builder, listNode);
-
- builder.returnResult();
- }
- });
- }
-
- private Type implementListConstructor(InstructionBuilder builder, Tree listNode)
- {
- // First, create an empty instance of ArrayList
-
- int count = listNode.getChildCount();
-
- builder.newInstance(ArrayList.class);
- builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class);
-
- for (int i = 0; i < count; i++)
- {
- builder.dupe(); // the ArrayList
-
- Type expressionType = implementSubexpression(builder, null, listNode.getChild(i));
-
- boxIfPrimitive(builder, GenericsUtils.asClass(expressionType));
-
- // Add the value to the array, then pop off the returned boolean
- builder.invoke(ArrayListMethods.ADD).pop();
- }
-
- return ArrayList.class;
- }
-
- private void implementMapGetter(final Tree mapNode)
- {
- plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- implementMapConstructor(builder, mapNode);
-
- builder.returnResult();
- }
- });
- }
-
- private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode)
- {
- int count = mapNode.getChildCount();
- builder.newInstance(HashMap.class);
- builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
-
- for (int i = 0; i < count; i += 2)
- {
- builder.dupe();
-
- //build the key:
- Type keyType = implementSubexpression(builder, null, mapNode.getChild(i));
- boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
-
- //and the value:
- Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
- boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
-
- //put the value into the array, then pop off the returned object.
- builder.invoke(HashMapMethods.PUT).pop();
-
- }
-
- return HashMap.class;
- }
-
-
- private void implementNoOpSetter()
- {
- implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
- rootType.getName());
- }
-
- public void implementNoOpMethod(MethodDescription method, String format, Object... arguments)
- {
- final String message = String.format(format, arguments);
-
- plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- builder.throwException(RuntimeException.class, message);
- }
- });
- }
-
- /**
- * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
- * to be evaluated, and potentially coerced, so that they may be passed to the method.
- *
- * @param builder
- * constructs code
- * @param method
- * method to invoke
- * @param node
- * INVOKE or RANGEOP node
- * @param childOffset
- * offset within the node to the first child expression (1 in an INVOKE node because the
- * first child is the method name, 0 in a RANGEOP node)
- */
- private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
- {
- // We start with the target object for the method on top of the stack.
- // Next, we have to push each method parameter, which may include boxing/deboxing
- // and coercion. Once the code is in good shape, there's a lot of room to optimize
- // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary
- // trips through TypeCoercer). We might also want to have a local variable to store
- // the root object (result of getRoot()).
-
- Class[] parameterTypes = method.getParameterTypes();
-
- for (int i = 0; i < parameterTypes.length; i++)
- {
- Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset));
-
- // The value left on the stack is not primitive, and expressionType represents
- // its real type.
-
- Class parameterType = parameterTypes[i];
-
- if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType)))
- {
- boxIfPrimitive(builder, expressionType);
-
- builder.loadThis().getField(getDelegateField());
- builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType));
- builder.invoke(DelegateMethods.COERCE);
-
- if (parameterType.isPrimitive())
- {
- builder.castOrUnbox(parameterType.getName());
- } else
- {
- builder.checkcast(parameterType);
- }
- }
-
- // And that should leave an object of the correct type on the stack,
- // ready for the method invocation.
- }
-
- // Now the target object and all parameters are in place.
-
- builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(),
- method.getParameterTypes());
- }
-
- /**
- * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
- * peform the dereference.
- *
- * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
- * to advance the evaluation of the expression form the previous value to the current
- */
- private Term analyzeDerefNode(Type activeType, Tree node)
- {
- // The first child is the term.
-
- Tree term = node.getChild(0);
-
- boolean allowNull = node.getType() == SAFEDEREF;
-
- return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
- }
-
- private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling)
- {
- assertNodeType(term, IDENTIFIER, INVOKE);
-
- final Term simpleTerm = buildTerm(activeType, term);
-
- if (simpleTerm.genericType.isPrimitive())
- return simpleTerm;
-
- return simpleTerm.withCallback(new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- simpleTerm.callback.doBuild(builder);
-
- builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- switch (nullHandling)
- {
- // It is necessary to load a null onto the stack (even if there's already one
- // there) because of the verifier. It sees the return when the stack contains an
- // intermediate value (along the navigation chain) and thinks the method is
- // returning a value of the wrong type.
-
- case ALLOW:
- builder.loadNull().returnResult();
-
- case FORBID:
-
- builder.loadConstant(simpleTerm.description);
- builder.loadConstant(expression);
- builder.loadArgument(0);
-
- builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class,
- "nullTerm", String.class, String.class, Object.class);
- builder.throwException();
-
- break;
-
- }
- }
- });
- }
- });
- }
-
- private void assertNodeType(Tree node, int... expected)
- {
- int type = node.getType();
-
- for (int e : expected)
- {
- if (type == e)
- return;
- }
-
- throw unexpectedNodeType(node, expected);
- }
-
- private RuntimeException unexpectedNodeType(Tree node, int... expected)
- {
- List<String> tokenNames = CollectionFactory.newList();
-
- for (int i = 0; i < expected.length; i++)
- tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]);
-
- String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
- node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
- InternalUtils.joinSorted(tokenNames));
-
- return new RuntimeException(message);
- }
-
- private Term buildTerm(Type activeType, Tree termNode)
- {
- switch (termNode.getType())
- {
- case INVOKE:
-
- return buildInvokeTerm(activeType, termNode);
-
- case IDENTIFIER:
-
- return buildPropertyAccessTerm(activeType, termNode);
-
- default:
- throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER);
- }
- }
-
- private Term buildPropertyAccessTerm(Type activeType, Tree termNode)
- {
- String propertyName = termNode.getText();
-
- PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
-
- // Prefer the accessor over the field
-
- if (adapter.getReadMethod() != null)
- {
- return buildGetterMethodAccessTerm(activeType, propertyName,
- adapter.getReadMethod());
- }
-
- if (adapter.getField() != null)
- {
- return buildPublicFieldAccessTerm(activeType, propertyName,
- adapter.getField());
- }
-
- throw new RuntimeException(String.format(
- "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
- adapter.getBeanType().getName()));
- }
-
- public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName)
- {
- Class activeClass = GenericsUtils.asClass(activeType);
-
- ClassPropertyAdapter classAdapter = access.getAdapter(activeClass);
- PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
-
- if (adapter == null)
- {
- final List<String> names = classAdapter.getPropertyNames();
- final String className = activeClass.getName();
- throw new UnknownValueException(String.format(
- "Class %s does not contain a property (or public field) named '%s'.", className, propertyName),
- new AvailableValues("Properties (and public fields)", names));
- }
- return adapter;
- }
-
- private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod)
- {
- Type returnType = GenericsUtils.extractActualType(activeType, readMethod);
-
- return new Term(returnType, propertyName, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeMethod(builder, readMethod, null, 0);
-
- Type genericType = GenericsUtils.extractActualType(activeType, readMethod);
-
- castToGenericType(builder, readMethod.getReturnType(), genericType);
- }
- });
- }
-
- private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field)
- {
- final Type fieldType = GenericsUtils.extractActualType(activeType, field);
-
- return new Term(fieldType, propertyName, new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- Class rawFieldType = field.getType();
-
- String rawTypeName = PlasticUtils.toTypeName(rawFieldType);
- String containingClassName = field.getDeclaringClass().getName();
- String fieldName = field.getName();
-
- if (isStatic(field))
- {
- // We've gone to the trouble of loading the root object, or navigated to some other object,
- // but we don't need or want the instance, since it's a static field we're accessing.
- // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but
- // access to public fields is relatively rare, and the cost is just the unused bytecode.
-
- builder.pop();
-
- builder.getStaticField(containingClassName, fieldName, rawTypeName);
-
- } else
- {
- builder.getField(containingClassName, fieldName, rawTypeName);
- }
-
- castToGenericType(builder, rawFieldType, fieldType);
- }
-
- });
- }
-
- /**
- * Casts the results of a field read or method invocation based on generic information.
- *
- * @param builder
- * used to add instructions
- * @param rawType
- * the simple type (often Object) of the field (or method return type)
- * @param genericType
- * the generic Type, from which parameterizations can be determined
- */
- private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
- {
- if (!genericType.equals(rawType))
- {
- Class castType = GenericsUtils.asClass(genericType);
- builder.checkcast(castType);
- }
- }
-
- private Term buildInvokeTerm(final Type activeType, final Tree invokeNode)
- {
- String methodName = invokeNode.getChild(0).getText();
-
- int parameterCount = invokeNode.getChildCount() - 1;
-
- Class activeClass = GenericsUtils.asClass(activeType);
-
- final Method method = findMethod(activeClass, methodName, parameterCount);
-
- if (method.getReturnType().equals(void.class))
- throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(),
- methodName));
-
- Type returnType = GenericsUtils.extractActualType(activeType, method);
-
- return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
- {
- public void doBuild(InstructionBuilder builder)
- {
- invokeMethod(builder, method, invokeNode, 1);
-
- Type genericType = GenericsUtils.extractActualType(activeType, method);
-
- castToGenericType(builder, method.getReturnType(), genericType);
- }
- }
- );
- }
-
- private Method findMethod(Class activeType, String methodName, int parameterCount)
- {
- Class searchType = activeType;
-
- while (true)
- {
-
- for (Method method : searchType.getMethods())
- {
- if (method.getParameterTypes().length == parameterCount
- && method.getName().equalsIgnoreCase(methodName))
- return method;
- }
-
- // TAP5-330
- if (searchType != Object.class)
- {
- searchType = Object.class;
- } else
- {
- throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
- activeType.getName(), methodName));
- }
- }
- }
-
- public void boxIfPrimitive(InstructionBuilder builder, Type termType)
- {
- boxIfPrimitive(builder, GenericsUtils.asClass(termType));
- }
-
- public void boxIfPrimitive(InstructionBuilder builder, Class termType)
- {
- if (termType.isPrimitive())
- builder.boxPrimitive(termType.getName());
- }
-
- public Class implementNotExpression(InstructionBuilder builder, final Tree notNode)
- {
- Type expressionType = implementSubexpression(builder, null, notNode.getChild(0));
-
- boxIfPrimitive(builder, expressionType);
-
- // Now invoke the delegate invert() method
-
- builder.loadThis().getField(getDelegateField());
-
- builder.swap().invoke(DelegateMethods.INVERT);
-
- return boolean.class;
- }
-
- /**
- * Defer creation of the delegate field unless actually needed.
- */
- private PlasticField getDelegateField()
- {
- if (delegateField == null)
- delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject(
- sharedDelegate);
-
- return delegateField;
- }
- }
-
- public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
- PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
- {
- this.access = access;
- this.proxyFactory = proxyFactory;
- this.typeCoercer = typeCoercer;
- this.interner = interner;
-
- literalTrue = createLiteralConduit(Boolean.class, true);
- literalFalse = createLiteralConduit(Boolean.class, false);
- literalNull = createLiteralConduit(Void.class, null);
-
- sharedDelegate = new PropertyConduitDelegate(typeCoercer);
- }
-
- @PostInjection
- public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub)
- {
- hub.clearOnInvalidation(cache);
- }
-
-
- public PropertyConduit create(Class rootClass, String expression)
- {
- assert rootClass != null;
- assert InternalUtils.isNonBlank(expression);
-
- MultiKey key = new MultiKey(rootClass, expression);
-
- PropertyConduit result = cache.get(key);
-
- if (result == null)
- {
- result = build(rootClass, expression);
- cache.put(key, result);
- }
-
- return result;
- }
-
- /**
- * Builds a subclass of {@link PropertyConduitDelegate} that implements the
- * get() and set() methods and overrides the
- * constructor. In a worst-case race condition, we may build two (or more)
- * conduits for the same
- * rootClass/expression, and it will get sorted out when the conduit is
- * stored into the cache.
- *
- * @param rootClass
- * class of root object for expression evaluation
- * @param expression
- * expression to be evaluated
- * @return the conduit
- */
- private PropertyConduit build(final Class rootClass, String expression)
- {
- Tree tree = parse(expression);
-
- try
- {
- switch (tree.getType())
- {
- case TRUE:
-
- return literalTrue;
-
- case FALSE:
-
- return literalFalse;
-
- case NULL:
-
- return literalNull;
-
- case INTEGER:
-
- // Leading '+' may screw this up.
- // TODO: Singleton instance for "0", maybe "1"?
-
- return createLiteralConduit(Long.class, new Long(tree.getText()));
-
- case DECIMAL:
-
- // Leading '+' may screw this up.
- // TODO: Singleton instance for "0.0"?
-
- return createLiteralConduit(Double.class, new Double(tree.getText()));
-
- case STRING:
-
- return createLiteralConduit(String.class, tree.getText());
-
- case RANGEOP:
-
- Tree fromNode = tree.getChild(0);
- Tree toNode = tree.getChild(1);
-
- // If the range is defined as integers (not properties, etc.)
- // then it is possible to calculate the value here, once, and not
- // build a new class.
-
- if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER)
- break;
-
- int from = Integer.parseInt(fromNode.getText());
- int to = Integer.parseInt(toNode.getText());
-
- IntegerRange ir = new IntegerRange(from, to);
-
- return createLiteralConduit(IntegerRange.class, ir);
-
- case THIS:
-
- return createLiteralThisPropertyConduit(rootClass);
-
- default:
- break;
- }
-
- return proxyFactory.createProxy(InternalPropertyConduit.class,
- new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
- } catch (Exception ex)
- {
- throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
- expression, ExceptionUtils.toMessage(ex)), expression, ex);
- }
- }
-
- private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass)
- {
- return new PropertyConduit()
- {
- public Object get(Object instance)
- {
- return instance;
- }
-
- public void set(Object instance, Object value)
- {
- throw new RuntimeException("Literal values are not updateable.");
- }
-
- public Class getPropertyType()
- {
- return rootClass;
- }
-
- public Type getPropertyGenericType()
- {
- return rootClass;
- }
-
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return invariantAnnotationProvider.getAnnotation(annotationClass);
- }
- };
- }
-
- private <T> PropertyConduit createLiteralConduit(Class<T> type, T value)
- {
- return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format(
- "LiteralPropertyConduit[%s]", value), value);
- }
-
- private Tree parse(String expression)
- {
- InputStream is = new ByteArrayInputStream(expression.getBytes());
-
- ANTLRInputStream ais;
-
- try
- {
- ais = new ANTLRInputStream(is);
- } catch (IOException ex)
- {
- throw new RuntimeException(ex);
- }
-
- PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais);
-
- CommonTokenStream tokens = new CommonTokenStream(lexer);
-
- PropertyExpressionParser parser = new PropertyExpressionParser(tokens);
-
- try
- {
- return (Tree) parser.start().getTree();
- } catch (Exception ex)
- {
- throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
- ex.getMessage()), ex);
- }
- }
-
- /**
- * May be invoked from fabricated PropertyConduit instances.
- */
- @SuppressWarnings("unused")
- public static NullPointerException nullTerm(String term, String expression, Object root)
- {
- String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term,
- expression, root);
-
- return new NullPointerException(message);
- }
-
- private static String toUniqueId(Method method)
- {
- StringBuilder builder = new StringBuilder(method.getName()).append("(");
- String sep = "";
-
- for (Class parameterType : method.getParameterTypes())
- {
- builder.append(sep);
- builder.append(PlasticUtils.toTypeName(parameterType));
-
- sep = ",";
- }
-
- return builder.append(")").toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
deleted file mode 100644
index 7b2b7ab..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2006 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.util;
-
-import java.util.Iterator;
-
-/**
- * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the
- * finish value).
- */
-public final class IntegerRange implements Iterable<Integer>
-{
- private final int start;
-
- private final int finish;
-
- private class RangeIterator implements Iterator<Integer>
- {
- private final int increment;
-
- private int value = start;
-
- private boolean hasNext = true;
-
- RangeIterator()
- {
- increment = start < finish ? +1 : -1;
- }
-
- public boolean hasNext()
- {
- return hasNext;
- }
-
- public Integer next()
- {
- if (!hasNext) throw new IllegalStateException();
-
- int result = value;
-
- hasNext = value != finish;
-
- value += increment;
-
- return result;
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
-
- }
-
- public IntegerRange(final int start, final int finish)
- {
- this.start = start;
- this.finish = finish;
- }
-
- public int getFinish()
- {
- return finish;
- }
-
- public int getStart()
- {
- return start;
- }
-
- @Override
- public String toString()
- {
- return String.format("%d..%d", start, finish);
- }
-
- /**
- * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with
- * the Tapestry Loop component, but also with the Java for loop!
- */
- public Iterator<Integer> iterator()
- {
- return new RangeIterator();
- }
-
- @Override
- public int hashCode()
- {
- final int PRIME = 31;
-
- int result = PRIME + finish;
-
- result = PRIME * result + start;
-
- return result;
- }
-
- /**
- * Returns true if the other object is an IntegerRange with the same start and finish values.
- */
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- final IntegerRange other = (IntegerRange) obj;
- if (finish != other.finish) return false;
-
- return start == other.start;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
deleted file mode 100644
index 503bb1f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2006 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.util;
-
-import java.util.Arrays;
-
-/**
- * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested
- * maps.
- */
-public final class MultiKey
-{
- private static final int PRIME = 31;
-
- private final Object[] values;
-
- private final int hashCode;
-
- /**
- * Creates a new instance from the provided values. It is assumed that the values provided are good map keys
- * themselves -- immutable, with proper implementations of equals() and hashCode().
- *
- * @param values
- */
- public MultiKey(Object... values)
- {
- this.values = values;
-
- hashCode = PRIME * Arrays.hashCode(this.values);
- }
-
- @Override
- public int hashCode()
- {
- return hashCode;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- final MultiKey other = (MultiKey) obj;
-
- return Arrays.equals(values, other.values);
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder("MultiKey[");
-
- boolean first = true;
-
- for (Object o : values)
- {
- if (!first)
- builder.append(", ");
-
- builder.append(o);
-
- first = false;
- }
-
- builder.append("]");
-
- return builder.toString();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
deleted file mode 100644
index 16b4fca..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.services;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.ioc.Messages;
-
-/**
- * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
- * class. Also provides support to the model by generating validation information for individual fields.
- * <p/>
- * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
- * org.apache.tapestry5.corelib.components.Grid} comopnents.
- *
- * @see org.apache.tapestry5.services.PropertyConduitSource
- */
-public interface BeanModelSource
-{
- /**
- * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
- * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
- * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
- * properties are derived from the property names, but if the component's message catalog has keys of the form
- * <code>propertyName-label</code>, then those will be used instead.
- * <p/>
- * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
- *
- * @param beanClass class of object to be edited
- * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only
- * read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm},
- * etc.). If false, then both read-only and read-write properties will be included
- * (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link
- * org.apache.tapestry5.corelib.components.BeanDisplay}).
- * @param messages Used to find explicit overrides of
- * @return a model
- * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link
- * #createEditModel(Class, org.apache.tapestry5.ioc.Messages)}
- */
- <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages);
-
- /**
- * Creates a model for display purposes; this may include properties which are read-only.
- *
- * @param beanClass class of object to be edited
- * @param messages
- * @return a model containing properties that can be presented to the user
- */
- <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages);
-
- /**
- * Creates a model for edit and update purposes, only properties that are fully read-write are included.
- *
- * @param beanClass class of object to be edited
- * @param messages
- * @return a model containing properties that can be presented to the user
- */
- <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
deleted file mode 100644
index c901d3a..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClasses.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2008, 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.services;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker annotation used to inject the correct {@link org.apache.tapestry5.services.InvalidationEventHub} service
- * responsible for invalidations when underlying component class files are changed.
- *
- * @since 5.1.0.0
- */
-@Target(
-{ ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface ComponentClasses
-{
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
deleted file mode 100644
index e342c3f..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLayer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.services;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * Marker annotation used to identify a service from the component layer that conflicts, in terms of service interface,
- * with a service from elsewhere. In particular, this is used to disambiguate {@link org.apache.tapestry5.ioc.services.PlasticProxyFactory} which has one implementation (marked with {@link
- * org.apache.tapestry5.ioc.services.Builtin} and another with this annotation.
- */
-@Target(
- {PARAMETER, FIELD})
-@Retention(RUNTIME)
-@Documented
-public @interface ComponentLayer
-{
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
deleted file mode 100644
index 77b028e..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2006, 2007, 2008, 2011, 2012 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.services;
-
-import java.util.Map;
-
-/**
- * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple
- * event hub services implementing this interface, each with a specific marker annotation; each can register listeners
- * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support
- * for:
- * <dl>
- * <dt>message catalog resources
- * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation
- * <dt>component templates
- * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation
- * <dt>component classes
- * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation
- * </dl>
- * <p/>
- * Starting in Tapestry 5.3, these services are disabled in production (it does nothing).
- *
- * @since 5.1.0.0
- */
-public interface InvalidationEventHub
-{
- /**
- * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the
- * receiver may discard any cached data that may have been invalidated). Does nothing in production mode.
- *
- * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead}
- */
- void addInvalidationListener(InvalidationListener listener);
-
- /**
- * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode.
- *
- * @since 5.4
- */
- void addInvalidationCallback(Runnable callback);
-
- /**
- * Adds a callback that clears the map.
- *
- * @since 5.4
- */
- void clearOnInvalidation(Map<?,?> map);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
deleted file mode 100644
index b9b4aa3..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/InvalidationListener.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2006, 2007, 2012 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.services;
-
-/**
- * Interface for objects that may cache information that can be invalidated. Invalidation occurs when external files,
- * from which in-memory data is cached, is determined to have changed. Granularity is very limited; when any external
- * file is found to have changed, the event is fired (with the expectation that the cleared cache will be repopulated as
- * necessary).
- *
- * @see org.apache.tapestry5.services.InvalidationEventHub
- * @since 5.1.0.0
- * @deprecated In 5.4; use {@link InvalidationEventHub#addInvalidationCallback(Runnable)} instead
- */
-public interface InvalidationListener
-{
- /**
- * Invoked to indicate that some object is invalid. The receiver should clear its cache.
- */
- void objectWasInvalidated();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
deleted file mode 100644
index 312cd60..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2007, 2008, 2009 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.services;
-
-import org.apache.tapestry5.PropertyConduit;
-
-/**
- * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
- * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
- * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
- */
-public interface PropertyConduitSource
-{
- /**
- * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it
- * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if
- * a change to component classes is observed.
- * <p/>
- * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
- * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
- * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
- * and classloaders).
- *
- * @param rootType the type of the root object to which the expression is applied
- * @param expression expression to be evaluated on instances of the root class
- * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.)
- */
- PropertyConduit create(Class rootType, String expression);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/build.gradle
----------------------------------------------------------------------
diff --git a/tapestry-ioc/build.gradle b/tapestry-ioc/build.gradle
index e890f7e..5a5321f 100644
--- a/tapestry-ioc/build.gradle
+++ b/tapestry-ioc/build.gradle
@@ -4,6 +4,7 @@ dependencies {
compile project(':tapestry-func')
compile project(':tapestry5-annotations')
compile project(":plastic")
+ compile project(":beanmodel")
provided project(':tapestry-test')
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
deleted file mode 100644
index 1f0e744..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2007, 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.ioc;
-
-import java.lang.annotation.Annotation;
-
-/**
- * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method,
- * a Class, or some other source).
- */
-public interface AnnotationProvider
-{
- /**
- * Searches for the specified annotation, returning the matching annotation instance.
- *
- * @param <T>
- * @param annotationClass used to select the annotation to return
- * @return the annotation, or null if not found
- */
- <T extends Annotation> T getAnnotation(Class<T> annotationClass);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
deleted file mode 100644
index 37b6551..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Locatable.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2006, 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.ioc;
-
-/**
- * Interface implemented by objects which carry a location tag. Defines a readable property, location.
- */
-@SuppressWarnings({"JavaDoc"})
-public interface Locatable
-{
- /**
- * Returns the location associated with this object for error reporting purposes.
- */
- Location getLocation();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
deleted file mode 100644
index e6688c2..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Location.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2006 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.ioc;
-
-/**
- * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line
- * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be
- * tracked backwards to the files from which they were parsed or otherwise constructed.
- */
-public interface Location
-{
- /**
- * The resource from which the object tagged with a location was derived.
- */
- Resource getResource();
-
- /**
- * The line number within the resource, if known, or -1 otherwise.
- */
- int getLine();
-
- /**
- * The column number within the line if known, or -1 otherwise.
- */
- int getColumn();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
deleted file mode 100644
index e90eb65..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2006 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.ioc;
-
-/**
- * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message
- * key.
- */
-public interface MessageFormatter
-{
- /**
- * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of
- * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of
- * the class).
- *
- * @param args
- * @return formatted string
- */
- String format(Object... args);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
deleted file mode 100644
index ba7452c..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Messages.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2006, 2007, 2012 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.ioc;
-
-import java.util.Set;
-
-/**
- * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
- * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
- * java.util.ResourceBundle} with some changes.
- */
-public interface Messages
-{
- /**
- * Returns true if the bundle contains the named key.
- */
- boolean contains(String key);
-
- /**
- * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version
- * of the key is returned (converted to upper case and enclosed in brackets).
- *
- * @param key
- * @return localized message for key, or placeholder
- */
- String get(String key);
-
- /**
- * Returns a formatter for the message, which can be used to substitute arguments (as per {@link
- * java.util.Formatter}).
- *
- * @param key
- * @return formattable object
- */
- MessageFormatter getFormatter(String key);
-
- /**
- * Convenience for accessing a formatter and formatting a localized message with arguments.
- */
- String format(String key, Object... args);
-
- /**
- * Returns a set of all the keys for which this instance may provide a value.
- *
- * @return set of keys
- * @since 5.4
- */
- Set<String> getKeys();
-}
[06/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
new file mode 100644
index 0000000..701420f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -0,0 +1,1563 @@
+// Copyright 2007-2013 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 org.antlr.runtime.ANTLRInputStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.tree.Tree;
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.PropertyConduit2;
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
+import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
+import org.apache.tapestry5.internal.util.IntegerRange;
+import org.apache.tapestry5.internal.util.MultiKey;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.annotations.PostInjection;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.*;
+import org.apache.tapestry5.services.ComponentClasses;
+import org.apache.tapestry5.services.ComponentLayer;
+import org.apache.tapestry5.services.InvalidationEventHub;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
+
+public class PropertyConduitSourceImpl implements PropertyConduitSource
+{
+ static class ConduitMethods
+ {
+ private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
+
+ private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
+ Object.class);
+
+ private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
+ "getPropertyType");
+
+ private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class,
+ "getPropertyGenericType");
+
+ private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
+ "getPropertyName");
+
+ private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
+ "getAnnotation", Class.class);
+
+ }
+
+ static class DelegateMethods
+ {
+ static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
+
+ static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
+
+ static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class);
+ }
+
+ static class ArrayListMethods
+ {
+ static final Method ADD = getMethod(ArrayList.class, "add", Object.class);
+ }
+
+ static class HashMapMethods
+ {
+ static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class);
+ }
+
+ private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadNull().returnResult();
+ }
+ };
+
+ private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
+ {Object.class.getName()};
+
+ @SuppressWarnings("unchecked")
+ private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
+ {
+ try
+ {
+ return containingClass.getMethod(name, parameterTypes);
+ } catch (NoSuchMethodException ex)
+ {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+
+ private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
+ {
+ return new MethodDescription(getMethod(containingClass, name, parameterTypes));
+ }
+
+ private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
+
+ /**
+ * How are null values in intermdiate terms to be handled?
+ */
+ private enum NullHandling
+ {
+ /**
+ * Add code to check for null and throw exception if null.
+ */
+ FORBID,
+
+ /**
+ * Add code to check for null and short-circuit (i.e., the "?."
+ * safe-dereference operator)
+ */
+ ALLOW
+ }
+
+ /**
+ * One term in an expression. Expressions start with some root type and each term advances
+ * to a new type.
+ */
+ private class Term
+ {
+ /**
+ * The generic type of the term.
+ */
+ final Type type;
+
+ final Class genericType;
+
+ /**
+ * Describes the term, for use in error messages.
+ */
+ final String description;
+
+ final AnnotationProvider annotationProvider;
+
+ /**
+ * Callback that will implement the term.
+ */
+ final InstructionBuilderCallback callback;
+
+ Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
+ InstructionBuilderCallback callback)
+ {
+ this.type = type;
+ this.genericType = genericType;
+ this.description = description;
+ this.annotationProvider = annotationProvider;
+ this.callback = callback;
+ }
+
+ Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback)
+ {
+ this(type, GenericsUtils.asClass(type), description, annotationProvider, callback);
+ }
+
+ Term(Type type, String description, InstructionBuilderCallback callback)
+ {
+ this(type, description, null, callback);
+ }
+
+ /**
+ * Returns a clone of this Term with a new callback.
+ */
+ Term withCallback(InstructionBuilderCallback newCallback)
+ {
+ return new Term(type, genericType, description, annotationProvider, newCallback);
+ }
+ }
+
+ private final PropertyAccess access;
+
+ private final PlasticProxyFactory proxyFactory;
+
+ private final TypeCoercer typeCoercer;
+
+ private final StringInterner interner;
+
+ /**
+ * Keyed on combination of root class and expression.
+ */
+ private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap();
+
+ private final Invariant invariantAnnotation = new Invariant()
+ {
+ public Class<? extends Annotation> annotationType()
+ {
+ return Invariant.class;
+ }
+ };
+
+ private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider()
+ {
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ if (annotationClass == Invariant.class)
+ return annotationClass.cast(invariantAnnotation);
+
+ return null;
+ }
+ };
+
+ private final PropertyConduit literalTrue;
+
+ private final PropertyConduit literalFalse;
+
+ private final PropertyConduit literalNull;
+
+ private final PropertyConduitDelegate sharedDelegate;
+
+ /**
+ * Encapsulates the process of building a PropertyConduit instance from an
+ * expression, as an {@link PlasticClassTransformer}.
+ */
+ class PropertyConduitBuilder implements PlasticClassTransformer
+ {
+ private final Class rootType;
+
+ private final String expression;
+
+ private final Tree tree;
+
+ private Class conduitPropertyType;
+
+ private Type conduitPropertyGenericType;
+
+ private String conduitPropertyName;
+
+ private AnnotationProvider annotationProvider = nullAnnotationProvider;
+
+ private PlasticField delegateField;
+
+ private PlasticClass plasticClass;
+
+ private PlasticMethod getRootMethod, navMethod;
+
+ PropertyConduitBuilder(Class rootType, String expression, Tree tree)
+ {
+ this.rootType = rootType;
+ this.expression = expression;
+ this.tree = tree;
+ }
+
+ public void transform(PlasticClass plasticClass)
+ {
+ this.plasticClass = plasticClass;
+
+ // Create the various methods; also determine the conduit's property type, property name and identify
+ // the annotation provider.
+
+ implementNavMethodAndAccessors();
+
+ implementOtherMethods();
+
+ plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
+ }
+
+ private void implementOtherMethods()
+ {
+ PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class,
+ "annotationProvider").inject(annotationProvider);
+
+ plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField);
+
+ plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadConstant(conduitPropertyName).returnResult();
+ }
+ });
+
+ final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject(
+ conduitPropertyType);
+
+ plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadThis().getField(propertyTypeField).returnResult();
+ }
+ });
+
+ final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject(
+ conduitPropertyGenericType);
+
+ plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadThis().getField(propertyGenericTypeField).returnResult();
+ }
+ });
+ }
+
+ /**
+ * Creates a method that does a conversion from Object to the expected root type, with
+ * a null check.
+ */
+ private void implementGetRoot()
+ {
+ getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
+ SINGLE_OBJECT_ARGUMENT, null);
+
+ getRootMethod.changeImplementation(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.throwException(NullPointerException.class,
+ String.format("Root object of property expression '%s' is null.", expression));
+ }
+ });
+
+ builder.checkcast(rootType).returnResult();
+ }
+ });
+ }
+
+ private boolean isLeaf(Tree node)
+ {
+ int type = node.getType();
+
+ return type != DEREF && type != SAFEDEREF;
+ }
+
+ private void implementNavMethodAndAccessors()
+ {
+ implementGetRoot();
+
+ // First, create the navigate method.
+
+ final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
+
+ Type activeType = rootType;
+
+ Tree node = tree;
+
+ while (!isLeaf(node))
+ {
+ Term term = analyzeDerefNode(activeType, node);
+
+ callbacks.add(term.callback);
+
+ activeType = term.type;
+
+ // Second term is the continuation, possibly another chained
+ // DEREF, etc.
+ node = node.getChild(1);
+ }
+
+ Class activeClass = GenericsUtils.asClass(activeType);
+
+ if (callbacks.isEmpty())
+ {
+ navMethod = getRootMethod;
+ } else
+ {
+ navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
+ SINGLE_OBJECT_ARGUMENT, null);
+
+ navMethod.changeImplementation(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+
+ for (InstructionBuilderCallback callback : callbacks)
+ {
+ callback.doBuild(builder);
+ }
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ implementAccessors(activeType, node);
+ }
+
+ private void implementAccessors(Type activeType, Tree node)
+ {
+ switch (node.getType())
+ {
+ case IDENTIFIER:
+
+ implementPropertyAccessors(activeType, node);
+
+ return;
+
+ case INVOKE:
+
+ // So, at this point, we have the navigation method written
+ // and it covers all but the terminal
+ // de-reference. node is an IDENTIFIER or INVOKE. We're
+ // ready to use the navigation
+ // method to implement get() and set().
+
+ implementMethodAccessors(activeType, node);
+
+ return;
+
+ case RANGEOP:
+
+ // As currently implemented, RANGEOP can only appear as the
+ // top level, which
+ // means we didn't need the navigate method after all.
+
+ implementRangeOpGetter(node);
+ implementNoOpSetter();
+
+ conduitPropertyType = IntegerRange.class;
+ conduitPropertyGenericType = IntegerRange.class;
+
+ return;
+
+ case LIST:
+
+ implementListGetter(node);
+ implementNoOpSetter();
+
+ conduitPropertyType = List.class;
+ conduitPropertyGenericType = List.class;
+
+ return;
+
+ case MAP:
+ implementMapGetter(node);
+ implementNoOpSetter();
+
+ conduitPropertyType = Map.class;
+ conduitPropertyGenericType = Map.class;
+
+ return;
+
+
+ case NOT:
+ implementNotOpGetter(node);
+ implementNoOpSetter();
+
+ conduitPropertyType = boolean.class;
+ conduitPropertyGenericType = boolean.class;
+
+ return;
+
+ default:
+ throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
+ }
+ }
+
+ public void implementMethodAccessors(final Type activeType, final Tree invokeNode)
+ {
+ final Term term = buildInvokeTerm(activeType, invokeNode);
+
+ implementNoOpSetter();
+
+ conduitPropertyName = term.description;
+ conduitPropertyType = term.genericType;
+ conduitPropertyGenericType = term.genericType;
+ annotationProvider = term.annotationProvider;
+
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ term.callback.doBuild(builder);
+
+ boxIfPrimitive(builder, conduitPropertyType);
+
+ builder.returnResult();
+ }
+ });
+
+ implementNoOpSetter();
+ }
+
+ public void implementPropertyAccessors(Type activeType, Tree identifierNode)
+ {
+ String propertyName = identifierNode.getText();
+
+ PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
+
+ conduitPropertyName = propertyName;
+ conduitPropertyType = adapter.getType();
+ conduitPropertyGenericType = getGenericType(adapter);
+ annotationProvider = adapter;
+
+ implementGetter(adapter);
+ implementSetter(adapter);
+ }
+
+ private Type getGenericType(PropertyAdapter adapter)
+ {
+ Type genericType = null;
+ if (adapter.getField() != null)
+ {
+ genericType = adapter.getField().getGenericType();
+ }
+ else if (adapter.getReadMethod() != null)
+ {
+ genericType = adapter.getReadMethod().getGenericReturnType();
+ }
+ else if (adapter.getWriteMethod() != null)
+ {
+ genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
+ }
+ else
+ {
+ throw new RuntimeException("Could not find accessor for property " + adapter.getName());
+ }
+
+ return genericType == null ? adapter.getType() : genericType;
+ }
+
+ private void implementSetter(PropertyAdapter adapter)
+ {
+ if (adapter.getWriteMethod() != null)
+ {
+ implementSetter(adapter.getWriteMethod());
+ return;
+ }
+
+ if (adapter.getField() != null && adapter.isUpdate())
+ {
+ implementSetter(adapter.getField());
+ return;
+ }
+
+ implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
+ rootType.getName());
+ }
+
+ private boolean isStatic(Member member)
+ {
+ return Modifier.isStatic(member.getModifiers());
+ }
+
+ private void implementSetter(final Field field)
+ {
+ if (isStatic(field))
+ {
+ plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+ builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ builder.returnResult();
+ }
+ });
+
+ return;
+ }
+
+ plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+ builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private void implementSetter(final Method writeMethod)
+ {
+ plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ Class propertyType = writeMethod.getParameterTypes()[0];
+ String propertyTypeName = PlasticUtils.toTypeName(propertyType);
+
+ builder.loadArgument(1).castOrUnbox(propertyTypeName);
+
+ builder.invoke(writeMethod);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private void implementGetter(PropertyAdapter adapter)
+ {
+ if (adapter.getReadMethod() != null)
+ {
+ implementGetter(adapter.getReadMethod());
+ return;
+ }
+
+ if (adapter.getField() != null)
+ {
+ implementGetter(adapter.getField());
+ return;
+ }
+
+ implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression,
+ rootType.getName());
+ }
+
+ private void implementGetter(final Field field)
+ {
+ if (isStatic(field))
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ // Cast not necessary here since the return type of get() is Object
+
+ boxIfPrimitive(builder, field.getType());
+
+ builder.returnResult();
+ }
+ });
+
+ return;
+ }
+
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ // Cast not necessary here since the return type of get() is Object
+
+ boxIfPrimitive(builder, field.getType());
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private void implementGetter(final Method readMethod)
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ invokeMethod(builder, readMethod, null, 0);
+
+ boxIfPrimitive(builder, conduitPropertyType);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private void implementRangeOpGetter(final Tree rangeNode)
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ // Put the delegate on top of the stack
+
+ builder.loadThis().getField(getDelegateField());
+
+ invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ /**
+ * @param node
+ * subexpression to invert
+ */
+ private void implementNotOpGetter(final Tree node)
+ {
+ // Implement get() as navigate, then do a method invocation based on node
+ // then, then pass (wrapped) result to delegate.invert()
+
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ Type expressionType = implementNotExpression(builder, node);
+
+ // Yes, we know this will always be the case, for now.
+
+ boxIfPrimitive(builder, expressionType);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ /**
+ * The first part of any implementation of get() or set(): invoke the navigation method
+ * and if the result is null, return immediately.
+ */
+ private void invokeNavigateMethod(InstructionBuilder builder)
+ {
+ builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
+
+ builder.dupe().when(Condition.NULL, RETURN_NULL);
+ }
+
+ /**
+ * Uses the builder to add instructions for a subexpression.
+ *
+ * @param builder
+ * used to add instructions
+ * @param activeType
+ * type of value on top of the stack when this code will execute, or null if no value on stack
+ * @param node
+ * defines the expression
+ * @return the expression type
+ */
+ private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
+ {
+ Term term;
+
+ while (true)
+ {
+ switch (node.getType())
+ {
+ case IDENTIFIER:
+ case INVOKE:
+
+ if (activeType == null)
+ {
+ invokeGetRootMethod(builder);
+
+ activeType = rootType;
+ }
+
+ term = buildTerm(activeType, node);
+
+ term.callback.doBuild(builder);
+
+ return term.type;
+
+ case INTEGER:
+
+ builder.loadConstant(new Long(node.getText()));
+
+ return long.class;
+
+ case DECIMAL:
+
+ builder.loadConstant(new Double(node.getText()));
+
+ return double.class;
+
+ case STRING:
+
+ builder.loadConstant(node.getText());
+
+ return String.class;
+
+ case DEREF:
+ case SAFEDEREF:
+
+ if (activeType == null)
+ {
+ invokeGetRootMethod(builder);
+
+ activeType = rootType;
+ }
+
+ term = analyzeDerefNode(activeType, node);
+
+ term.callback.doBuild(builder);
+
+ activeType = GenericsUtils.asClass(term.type);
+
+ node = node.getChild(1);
+
+ break;
+
+ case TRUE:
+ case FALSE:
+
+ builder.loadConstant(node.getType() == TRUE ? 1 : 0);
+
+ return boolean.class;
+
+ case LIST:
+
+ return implementListConstructor(builder, node);
+
+ case MAP:
+ return implementMapConstructor(builder, node);
+
+ case NOT:
+
+ return implementNotExpression(builder, node);
+
+ case THIS:
+
+ invokeGetRootMethod(builder);
+
+ return rootType;
+
+ case NULL:
+
+ builder.loadNull();
+
+ return Void.class;
+
+ default:
+ throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
+ IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
+ }
+ }
+ }
+
+ public void invokeGetRootMethod(InstructionBuilder builder)
+ {
+ builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+ }
+
+ private void implementListGetter(final Tree listNode)
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ implementListConstructor(builder, listNode);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private Type implementListConstructor(InstructionBuilder builder, Tree listNode)
+ {
+ // First, create an empty instance of ArrayList
+
+ int count = listNode.getChildCount();
+
+ builder.newInstance(ArrayList.class);
+ builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class);
+
+ for (int i = 0; i < count; i++)
+ {
+ builder.dupe(); // the ArrayList
+
+ Type expressionType = implementSubexpression(builder, null, listNode.getChild(i));
+
+ boxIfPrimitive(builder, GenericsUtils.asClass(expressionType));
+
+ // Add the value to the array, then pop off the returned boolean
+ builder.invoke(ArrayListMethods.ADD).pop();
+ }
+
+ return ArrayList.class;
+ }
+
+ private void implementMapGetter(final Tree mapNode)
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ implementMapConstructor(builder, mapNode);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode)
+ {
+ int count = mapNode.getChildCount();
+ builder.newInstance(HashMap.class);
+ builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
+
+ for (int i = 0; i < count; i += 2)
+ {
+ builder.dupe();
+
+ //build the key:
+ Type keyType = implementSubexpression(builder, null, mapNode.getChild(i));
+ boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
+
+ //and the value:
+ Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
+ boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
+
+ //put the value into the array, then pop off the returned object.
+ builder.invoke(HashMapMethods.PUT).pop();
+
+ }
+
+ return HashMap.class;
+ }
+
+
+ private void implementNoOpSetter()
+ {
+ implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
+ rootType.getName());
+ }
+
+ public void implementNoOpMethod(MethodDescription method, String format, Object... arguments)
+ {
+ final String message = String.format(format, arguments);
+
+ plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.throwException(RuntimeException.class, message);
+ }
+ });
+ }
+
+ /**
+ * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
+ * to be evaluated, and potentially coerced, so that they may be passed to the method.
+ *
+ * @param builder
+ * constructs code
+ * @param method
+ * method to invoke
+ * @param node
+ * INVOKE or RANGEOP node
+ * @param childOffset
+ * offset within the node to the first child expression (1 in an INVOKE node because the
+ * first child is the method name, 0 in a RANGEOP node)
+ */
+ private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
+ {
+ // We start with the target object for the method on top of the stack.
+ // Next, we have to push each method parameter, which may include boxing/deboxing
+ // and coercion. Once the code is in good shape, there's a lot of room to optimize
+ // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary
+ // trips through TypeCoercer). We might also want to have a local variable to store
+ // the root object (result of getRoot()).
+
+ Class[] parameterTypes = method.getParameterTypes();
+
+ for (int i = 0; i < parameterTypes.length; i++)
+ {
+ Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset));
+
+ // The value left on the stack is not primitive, and expressionType represents
+ // its real type.
+
+ Class parameterType = parameterTypes[i];
+
+ if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType)))
+ {
+ boxIfPrimitive(builder, expressionType);
+
+ builder.loadThis().getField(getDelegateField());
+ builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType));
+ builder.invoke(DelegateMethods.COERCE);
+
+ if (parameterType.isPrimitive())
+ {
+ builder.castOrUnbox(parameterType.getName());
+ } else
+ {
+ builder.checkcast(parameterType);
+ }
+ }
+
+ // And that should leave an object of the correct type on the stack,
+ // ready for the method invocation.
+ }
+
+ // Now the target object and all parameters are in place.
+
+ builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(),
+ method.getParameterTypes());
+ }
+
+ /**
+ * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
+ * peform the dereference.
+ *
+ * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
+ * to advance the evaluation of the expression form the previous value to the current
+ */
+ private Term analyzeDerefNode(Type activeType, Tree node)
+ {
+ // The first child is the term.
+
+ Tree term = node.getChild(0);
+
+ boolean allowNull = node.getType() == SAFEDEREF;
+
+ return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
+ }
+
+ private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling)
+ {
+ assertNodeType(term, IDENTIFIER, INVOKE);
+
+ final Term simpleTerm = buildTerm(activeType, term);
+
+ if (simpleTerm.genericType.isPrimitive())
+ return simpleTerm;
+
+ return simpleTerm.withCallback(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ simpleTerm.callback.doBuild(builder);
+
+ builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ switch (nullHandling)
+ {
+ // It is necessary to load a null onto the stack (even if there's already one
+ // there) because of the verifier. It sees the return when the stack contains an
+ // intermediate value (along the navigation chain) and thinks the method is
+ // returning a value of the wrong type.
+
+ case ALLOW:
+ builder.loadNull().returnResult();
+
+ case FORBID:
+
+ builder.loadConstant(simpleTerm.description);
+ builder.loadConstant(expression);
+ builder.loadArgument(0);
+
+ builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class,
+ "nullTerm", String.class, String.class, Object.class);
+ builder.throwException();
+
+ break;
+
+ }
+ }
+ });
+ }
+ });
+ }
+
+ private void assertNodeType(Tree node, int... expected)
+ {
+ int type = node.getType();
+
+ for (int e : expected)
+ {
+ if (type == e)
+ return;
+ }
+
+ throw unexpectedNodeType(node, expected);
+ }
+
+ private RuntimeException unexpectedNodeType(Tree node, int... expected)
+ {
+ List<String> tokenNames = CollectionFactory.newList();
+
+ for (int i = 0; i < expected.length; i++)
+ tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]);
+
+ String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
+ node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
+ InternalUtils.joinSorted(tokenNames));
+
+ return new RuntimeException(message);
+ }
+
+ private Term buildTerm(Type activeType, Tree termNode)
+ {
+ switch (termNode.getType())
+ {
+ case INVOKE:
+
+ return buildInvokeTerm(activeType, termNode);
+
+ case IDENTIFIER:
+
+ return buildPropertyAccessTerm(activeType, termNode);
+
+ default:
+ throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER);
+ }
+ }
+
+ private Term buildPropertyAccessTerm(Type activeType, Tree termNode)
+ {
+ String propertyName = termNode.getText();
+
+ PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
+
+ // Prefer the accessor over the field
+
+ if (adapter.getReadMethod() != null)
+ {
+ return buildGetterMethodAccessTerm(activeType, propertyName,
+ adapter.getReadMethod());
+ }
+
+ if (adapter.getField() != null)
+ {
+ return buildPublicFieldAccessTerm(activeType, propertyName,
+ adapter.getField());
+ }
+
+ throw new RuntimeException(String.format(
+ "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
+ adapter.getBeanType().getName()));
+ }
+
+ public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName)
+ {
+ Class activeClass = GenericsUtils.asClass(activeType);
+
+ ClassPropertyAdapter classAdapter = access.getAdapter(activeClass);
+ PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
+
+ if (adapter == null)
+ {
+ final List<String> names = classAdapter.getPropertyNames();
+ final String className = activeClass.getName();
+ throw new UnknownValueException(String.format(
+ "Class %s does not contain a property (or public field) named '%s'.", className, propertyName),
+ new AvailableValues("Properties (and public fields)", names));
+ }
+ return adapter;
+ }
+
+ private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod)
+ {
+ Type returnType = GenericsUtils.extractActualType(activeType, readMethod);
+
+ return new Term(returnType, propertyName, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeMethod(builder, readMethod, null, 0);
+
+ Type genericType = GenericsUtils.extractActualType(activeType, readMethod);
+
+ castToGenericType(builder, readMethod.getReturnType(), genericType);
+ }
+ });
+ }
+
+ private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field)
+ {
+ final Type fieldType = GenericsUtils.extractActualType(activeType, field);
+
+ return new Term(fieldType, propertyName, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ Class rawFieldType = field.getType();
+
+ String rawTypeName = PlasticUtils.toTypeName(rawFieldType);
+ String containingClassName = field.getDeclaringClass().getName();
+ String fieldName = field.getName();
+
+ if (isStatic(field))
+ {
+ // We've gone to the trouble of loading the root object, or navigated to some other object,
+ // but we don't need or want the instance, since it's a static field we're accessing.
+ // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but
+ // access to public fields is relatively rare, and the cost is just the unused bytecode.
+
+ builder.pop();
+
+ builder.getStaticField(containingClassName, fieldName, rawTypeName);
+
+ } else
+ {
+ builder.getField(containingClassName, fieldName, rawTypeName);
+ }
+
+ castToGenericType(builder, rawFieldType, fieldType);
+ }
+
+ });
+ }
+
+ /**
+ * Casts the results of a field read or method invocation based on generic information.
+ *
+ * @param builder
+ * used to add instructions
+ * @param rawType
+ * the simple type (often Object) of the field (or method return type)
+ * @param genericType
+ * the generic Type, from which parameterizations can be determined
+ */
+ private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
+ {
+ if (!genericType.equals(rawType))
+ {
+ Class castType = GenericsUtils.asClass(genericType);
+ builder.checkcast(castType);
+ }
+ }
+
+ private Term buildInvokeTerm(final Type activeType, final Tree invokeNode)
+ {
+ String methodName = invokeNode.getChild(0).getText();
+
+ int parameterCount = invokeNode.getChildCount() - 1;
+
+ Class activeClass = GenericsUtils.asClass(activeType);
+
+ final Method method = findMethod(activeClass, methodName, parameterCount);
+
+ if (method.getReturnType().equals(void.class))
+ throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(),
+ methodName));
+
+ Type returnType = GenericsUtils.extractActualType(activeType, method);
+
+ return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeMethod(builder, method, invokeNode, 1);
+
+ Type genericType = GenericsUtils.extractActualType(activeType, method);
+
+ castToGenericType(builder, method.getReturnType(), genericType);
+ }
+ }
+ );
+ }
+
+ private Method findMethod(Class activeType, String methodName, int parameterCount)
+ {
+ Class searchType = activeType;
+
+ while (true)
+ {
+
+ for (Method method : searchType.getMethods())
+ {
+ if (method.getParameterTypes().length == parameterCount
+ && method.getName().equalsIgnoreCase(methodName))
+ return method;
+ }
+
+ // TAP5-330
+ if (searchType != Object.class)
+ {
+ searchType = Object.class;
+ } else
+ {
+ throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
+ activeType.getName(), methodName));
+ }
+ }
+ }
+
+ public void boxIfPrimitive(InstructionBuilder builder, Type termType)
+ {
+ boxIfPrimitive(builder, GenericsUtils.asClass(termType));
+ }
+
+ public void boxIfPrimitive(InstructionBuilder builder, Class termType)
+ {
+ if (termType.isPrimitive())
+ builder.boxPrimitive(termType.getName());
+ }
+
+ public Class implementNotExpression(InstructionBuilder builder, final Tree notNode)
+ {
+ Type expressionType = implementSubexpression(builder, null, notNode.getChild(0));
+
+ boxIfPrimitive(builder, expressionType);
+
+ // Now invoke the delegate invert() method
+
+ builder.loadThis().getField(getDelegateField());
+
+ builder.swap().invoke(DelegateMethods.INVERT);
+
+ return boolean.class;
+ }
+
+ /**
+ * Defer creation of the delegate field unless actually needed.
+ */
+ private PlasticField getDelegateField()
+ {
+ if (delegateField == null)
+ delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject(
+ sharedDelegate);
+
+ return delegateField;
+ }
+ }
+
+ public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
+ PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
+ {
+ this.access = access;
+ this.proxyFactory = proxyFactory;
+ this.typeCoercer = typeCoercer;
+ this.interner = interner;
+
+ literalTrue = createLiteralConduit(Boolean.class, true);
+ literalFalse = createLiteralConduit(Boolean.class, false);
+ literalNull = createLiteralConduit(Void.class, null);
+
+ sharedDelegate = new PropertyConduitDelegate(typeCoercer);
+ }
+
+ @PostInjection
+ public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub)
+ {
+ hub.clearOnInvalidation(cache);
+ }
+
+
+ public PropertyConduit create(Class rootClass, String expression)
+ {
+ assert rootClass != null;
+ assert InternalUtils.isNonBlank(expression);
+
+ MultiKey key = new MultiKey(rootClass, expression);
+
+ PropertyConduit result = cache.get(key);
+
+ if (result == null)
+ {
+ result = build(rootClass, expression);
+ cache.put(key, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Builds a subclass of {@link PropertyConduitDelegate} that implements the
+ * get() and set() methods and overrides the
+ * constructor. In a worst-case race condition, we may build two (or more)
+ * conduits for the same
+ * rootClass/expression, and it will get sorted out when the conduit is
+ * stored into the cache.
+ *
+ * @param rootClass
+ * class of root object for expression evaluation
+ * @param expression
+ * expression to be evaluated
+ * @return the conduit
+ */
+ private PropertyConduit build(final Class rootClass, String expression)
+ {
+ Tree tree = parse(expression);
+
+ try
+ {
+ switch (tree.getType())
+ {
+ case TRUE:
+
+ return literalTrue;
+
+ case FALSE:
+
+ return literalFalse;
+
+ case NULL:
+
+ return literalNull;
+
+ case INTEGER:
+
+ // Leading '+' may screw this up.
+ // TODO: Singleton instance for "0", maybe "1"?
+
+ return createLiteralConduit(Long.class, new Long(tree.getText()));
+
+ case DECIMAL:
+
+ // Leading '+' may screw this up.
+ // TODO: Singleton instance for "0.0"?
+
+ return createLiteralConduit(Double.class, new Double(tree.getText()));
+
+ case STRING:
+
+ return createLiteralConduit(String.class, tree.getText());
+
+ case RANGEOP:
+
+ Tree fromNode = tree.getChild(0);
+ Tree toNode = tree.getChild(1);
+
+ // If the range is defined as integers (not properties, etc.)
+ // then it is possible to calculate the value here, once, and not
+ // build a new class.
+
+ if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER)
+ break;
+
+ int from = Integer.parseInt(fromNode.getText());
+ int to = Integer.parseInt(toNode.getText());
+
+ IntegerRange ir = new IntegerRange(from, to);
+
+ return createLiteralConduit(IntegerRange.class, ir);
+
+ case THIS:
+
+ return createLiteralThisPropertyConduit(rootClass);
+
+ default:
+ break;
+ }
+
+ return proxyFactory.createProxy(InternalPropertyConduit.class,
+ new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
+ } catch (Exception ex)
+ {
+ throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
+ expression, ExceptionUtils.toMessage(ex)), expression, ex);
+ }
+ }
+
+ private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass)
+ {
+ return new PropertyConduit()
+ {
+ public Object get(Object instance)
+ {
+ return instance;
+ }
+
+ public void set(Object instance, Object value)
+ {
+ throw new RuntimeException("Literal values are not updateable.");
+ }
+
+ public Class getPropertyType()
+ {
+ return rootClass;
+ }
+
+ public Type getPropertyGenericType()
+ {
+ return rootClass;
+ }
+
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return invariantAnnotationProvider.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+ private <T> PropertyConduit createLiteralConduit(Class<T> type, T value)
+ {
+ return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format(
+ "LiteralPropertyConduit[%s]", value), value);
+ }
+
+ private Tree parse(String expression)
+ {
+ InputStream is = new ByteArrayInputStream(expression.getBytes());
+
+ ANTLRInputStream ais;
+
+ try
+ {
+ ais = new ANTLRInputStream(is);
+ } catch (IOException ex)
+ {
+ throw new RuntimeException(ex);
+ }
+
+ PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais);
+
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+ PropertyExpressionParser parser = new PropertyExpressionParser(tokens);
+
+ try
+ {
+ return (Tree) parser.start().getTree();
+ } catch (Exception ex)
+ {
+ throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
+ ex.getMessage()), ex);
+ }
+ }
+
+ /**
+ * May be invoked from fabricated PropertyConduit instances.
+ */
+ @SuppressWarnings("unused")
+ public static NullPointerException nullTerm(String term, String expression, Object root)
+ {
+ String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term,
+ expression, root);
+
+ return new NullPointerException(message);
+ }
+
+ private static String toUniqueId(Method method)
+ {
+ StringBuilder builder = new StringBuilder(method.getName()).append("(");
+ String sep = "";
+
+ for (Class parameterType : method.getParameterTypes())
+ {
+ builder.append(sep);
+ builder.append(PlasticUtils.toTypeName(parameterType));
+
+ sep = ",";
+ }
+
+ return builder.append(")").toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
new file mode 100644
index 0000000..16b4fca
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
@@ -0,0 +1,70 @@
+// 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.services;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.Messages;
+
+/**
+ * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
+ * class. Also provides support to the model by generating validation information for individual fields.
+ * <p/>
+ * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
+ * org.apache.tapestry5.corelib.components.Grid} comopnents.
+ *
+ * @see org.apache.tapestry5.services.PropertyConduitSource
+ */
+public interface BeanModelSource
+{
+ /**
+ * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
+ * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
+ * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
+ * properties are derived from the property names, but if the component's message catalog has keys of the form
+ * <code>propertyName-label</code>, then those will be used instead.
+ * <p/>
+ * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
+ *
+ * @param beanClass class of object to be edited
+ * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only
+ * read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm},
+ * etc.). If false, then both read-only and read-write properties will be included
+ * (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link
+ * org.apache.tapestry5.corelib.components.BeanDisplay}).
+ * @param messages Used to find explicit overrides of
+ * @return a model
+ * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link
+ * #createEditModel(Class, org.apache.tapestry5.ioc.Messages)}
+ */
+ <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages);
+
+ /**
+ * Creates a model for display purposes; this may include properties which are read-only.
+ *
+ * @param beanClass class of object to be edited
+ * @param messages
+ * @return a model containing properties that can be presented to the user
+ */
+ <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages);
+
+ /**
+ * Creates a model for edit and update purposes, only properties that are fully read-write are included.
+ *
+ * @param beanClass class of object to be edited
+ * @param messages
+ * @return a model containing properties that can be presented to the user
+ */
+ <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
new file mode 100644
index 0000000..312cd60
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
@@ -0,0 +1,41 @@
+// Copyright 2007, 2008, 2009 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.services;
+
+import org.apache.tapestry5.PropertyConduit;
+
+/**
+ * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
+ * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
+ * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
+ */
+public interface PropertyConduitSource
+{
+ /**
+ * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it
+ * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if
+ * a change to component classes is observed.
+ * <p/>
+ * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
+ * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
+ * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
+ * and classloaders).
+ *
+ * @param rootType the type of the root object to which the expression is applied
+ * @param expression expression to be evaluated on instances of the root class
+ * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.)
+ */
+ PropertyConduit create(Class rootType, String expression);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/build.gradle
----------------------------------------------------------------------
diff --git a/commons/build.gradle b/commons/build.gradle
new file mode 100644
index 0000000..76850ef
--- /dev/null
+++ b/commons/build.gradle
@@ -0,0 +1,18 @@
+import org.gradle.plugins.ide.idea.model.*
+import t5build.*
+
+description = "Project including common classes for tapestry-core, tapestry-ioc and beanmodel."
+
+//apply plugin: JavaPlugin
+
+buildDir = 'target/gradle-build'
+
+dependencies {
+ compile project(":plastic")
+ compile project(":tapestry5-annotations")
+}
+
+jar {
+ manifest {
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
new file mode 100644
index 0000000..7b2b7ab
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
@@ -0,0 +1,125 @@
+// Copyright 2006 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.util;
+
+import java.util.Iterator;
+
+/**
+ * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the
+ * finish value).
+ */
+public final class IntegerRange implements Iterable<Integer>
+{
+ private final int start;
+
+ private final int finish;
+
+ private class RangeIterator implements Iterator<Integer>
+ {
+ private final int increment;
+
+ private int value = start;
+
+ private boolean hasNext = true;
+
+ RangeIterator()
+ {
+ increment = start < finish ? +1 : -1;
+ }
+
+ public boolean hasNext()
+ {
+ return hasNext;
+ }
+
+ public Integer next()
+ {
+ if (!hasNext) throw new IllegalStateException();
+
+ int result = value;
+
+ hasNext = value != finish;
+
+ value += increment;
+
+ return result;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ public IntegerRange(final int start, final int finish)
+ {
+ this.start = start;
+ this.finish = finish;
+ }
+
+ public int getFinish()
+ {
+ return finish;
+ }
+
+ public int getStart()
+ {
+ return start;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%d..%d", start, finish);
+ }
+
+ /**
+ * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with
+ * the Tapestry Loop component, but also with the Java for loop!
+ */
+ public Iterator<Integer> iterator()
+ {
+ return new RangeIterator();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int PRIME = 31;
+
+ int result = PRIME + finish;
+
+ result = PRIME * result + start;
+
+ return result;
+ }
+
+ /**
+ * Returns true if the other object is an IntegerRange with the same start and finish values.
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final IntegerRange other = (IntegerRange) obj;
+ if (finish != other.finish) return false;
+
+ return start == other.start;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
new file mode 100644
index 0000000..503bb1f
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
@@ -0,0 +1,86 @@
+// Copyright 2006 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.util;
+
+import java.util.Arrays;
+
+/**
+ * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested
+ * maps.
+ */
+public final class MultiKey
+{
+ private static final int PRIME = 31;
+
+ private final Object[] values;
+
+ private final int hashCode;
+
+ /**
+ * Creates a new instance from the provided values. It is assumed that the values provided are good map keys
+ * themselves -- immutable, with proper implementations of equals() and hashCode().
+ *
+ * @param values
+ */
+ public MultiKey(Object... values)
+ {
+ this.values = values;
+
+ hashCode = PRIME * Arrays.hashCode(this.values);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final MultiKey other = (MultiKey) obj;
+
+ return Arrays.equals(values, other.values);
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder("MultiKey[");
+
+ boolean first = true;
+
+ for (Object o : values)
+ {
+ if (!first)
+ builder.append(", ");
+
+ builder.append(o);
+
+ first = false;
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
new file mode 100644
index 0000000..1f0e744
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
@@ -0,0 +1,33 @@
+// Copyright 2007, 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.ioc;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method,
+ * a Class, or some other source).
+ */
+public interface AnnotationProvider
+{
+ /**
+ * Searches for the specified annotation, returning the matching annotation instance.
+ *
+ * @param <T>
+ * @param annotationClass used to select the annotation to return
+ * @return the annotation, or null if not found
+ */
+ <T extends Annotation> T getAnnotation(Class<T> annotationClass);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
new file mode 100644
index 0000000..37b6551
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
@@ -0,0 +1,27 @@
+// Copyright 2006, 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.ioc;
+
+/**
+ * Interface implemented by objects which carry a location tag. Defines a readable property, location.
+ */
+@SuppressWarnings({"JavaDoc"})
+public interface Locatable
+{
+ /**
+ * Returns the location associated with this object for error reporting purposes.
+ */
+ Location getLocation();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Location.java b/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
new file mode 100644
index 0000000..e6688c2
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
@@ -0,0 +1,38 @@
+// Copyright 2006 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.ioc;
+
+/**
+ * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line
+ * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be
+ * tracked backwards to the files from which they were parsed or otherwise constructed.
+ */
+public interface Location
+{
+ /**
+ * The resource from which the object tagged with a location was derived.
+ */
+ Resource getResource();
+
+ /**
+ * The line number within the resource, if known, or -1 otherwise.
+ */
+ int getLine();
+
+ /**
+ * The column number within the line if known, or -1 otherwise.
+ */
+ int getColumn();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
new file mode 100644
index 0000000..e90eb65
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
@@ -0,0 +1,32 @@
+// Copyright 2006 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.ioc;
+
+/**
+ * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message
+ * key.
+ */
+public interface MessageFormatter
+{
+ /**
+ * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of
+ * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of
+ * the class).
+ *
+ * @param args
+ * @return formatted string
+ */
+ String format(Object... args);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java b/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
new file mode 100644
index 0000000..ba7452c
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
@@ -0,0 +1,61 @@
+// Copyright 2006, 2007, 2012 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.ioc;
+
+import java.util.Set;
+
+/**
+ * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
+ * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
+ * java.util.ResourceBundle} with some changes.
+ */
+public interface Messages
+{
+ /**
+ * Returns true if the bundle contains the named key.
+ */
+ boolean contains(String key);
+
+ /**
+ * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version
+ * of the key is returned (converted to upper case and enclosed in brackets).
+ *
+ * @param key
+ * @return localized message for key, or placeholder
+ */
+ String get(String key);
+
+ /**
+ * Returns a formatter for the message, which can be used to substitute arguments (as per {@link
+ * java.util.Formatter}).
+ *
+ * @param key
+ * @return formattable object
+ */
+ MessageFormatter getFormatter(String key);
+
+ /**
+ * Convenience for accessing a formatter and formatting a localized message with arguments.
+ */
+ String format(String key, Object... args);
+
+ /**
+ * Returns a set of all the keys for which this instance may provide a value.
+ *
+ * @return set of keys
+ * @since 5.4
+ */
+ Set<String> getKeys();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
new file mode 100644
index 0000000..81d1f77
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -0,0 +1,143 @@
+// Copyright 2006, 2007, 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.ioc;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.services.MasterObjectProvider;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
+ * to objects or object instances available by other means. Services are accessed via service id, or
+ * (when appropriate)
+ * by just service interface. The Registry itself implements this interface, as does
+ * {@link org.apache.tapestry5.ioc.ServiceResources}.
+ */
+public interface ObjectLocator
+{
+ /**
+ * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
+ * implements the same
+ * interface as the actual service, and is used to instantiate the actual service only as needed
+ * (this is
+ * transparent to the application).
+ *
+ * @param <T>
+ * @param serviceId unique Service id used to locate the service object (may contain <em>symbols</em>,
+ * which
+ * will be expanded), case is ignored
+ * @param serviceInterface the interface implemented by the service (or an interface extended by the service
+ * interface)
+ * @return the service instance
+ * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
+ */
+ <T> T getService(String serviceId, Class<T> serviceInterface);
+
+ /**
+ * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+ * interface (which * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
+ * (not the service <em>implementation</em>), which may result in a failure due to extra
+ * matches.
+ *
+ * @param serviceInterface the interface the service implements
+ * @return the service's proxy
+ * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+ * services directly implement, or extend from, the service interface
+ * @see org.apache.tapestry5.ioc.annotations.Marker
+ */
+ <T> T getService(Class<T> serviceInterface);
+
+ /**
+ * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+ * interface (which * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
+ * (not the service <em>implementation</em>), which may result in a failure due to extra
+ * matches. The ability to specify marker annotation types was added in 5.3
+ *
+ * @param serviceInterface the interface the service implements
+ * @param markerTypes Markers used to select a specific service that implements the interface
+ * @return the service's proxy
+ * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+ * services directly implement, or extend from, the service interface
+ * @see org.apache.tapestry5.ioc.annotations.Marker
+ * @since 5.3
+ */
+ <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
+
+ /**
+ * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
+ *
+ * @param objectType the type of object to be returned
+ * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
+ * be
+ * obtained, which may be utilized in selecting an appropriate object, use
+ * <strong>null</strong> when annotations are not available (in which case, selection
+ * will
+ * be based only on the object type)
+ * @param <T>
+ * @return the requested object
+ * @see ObjectProvider
+ */
+ <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider);
+
+ /**
+ * Autobuilds a class by finding the public constructor with the most parameters. Services and other resources or
+ * dependencies will be injected into the parameters of the constructor and into private fields marked with the
+ * {@link Inject} annotation. There are two cases: constructing a service implementation, and constructing
+ * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
+ * just dependencies or objects provided via
+ * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
+ *
+ * @param <T>
+ * @param clazz the type of object to instantiate
+ * @return the instantiated instance
+ * @throws RuntimeException if the autobuild fails
+ * @see MasterObjectProvider
+ */
+ <T> T autobuild(Class<T> clazz);
+
+ /**
+ * Preferred version of {@link #autobuild(Class)} that tracks the operation using
+ * {@link OperationTracker#invoke(String, Invokable)}.
+ *
+ * @param <T>
+ * @param description description used with {@link OperationTracker}
+ * @param clazz the type of object to instantiate
+ * @return the instantiated instance
+ * @throws RuntimeException if the autobuild fails
+ * @see MasterObjectProvider
+ * @since 5.2.0
+ */
+ <T> T autobuild(String description, Class<T> clazz);
+
+ /**
+ * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
+ * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
+ * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
+ * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
+ * of autobuilding).
+ * <p/>
+ * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
+ * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
+ * (with dependencies).
+ *
+ * @param <T>
+ * @param interfaceClass the interface implemented by the proxy
+ * @param implementationClass a concrete class that implements the interface
+ * @return a proxy
+ * @see #autobuild(Class)
+ */
+ <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
+}
[10/15] tapestry-5 git commit: Third pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
Third pass creating the BeanModel and Commons packages.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/dd958465
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/dd958465
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/dd958465
Branch: refs/heads/beanmodel-split
Commit: dd9584659823c87f014a1cf57c7be592eedfa4c6
Parents: c9e97d6
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 17:33:54 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 17:33:54 2014 -0200
----------------------------------------------------------------------
.../tapestry5/internal/BeanModelUtils.java | 145 ------------
.../internal/InternalBeanModelUtils.java | 145 ++++++++++++
.../internal/beaneditor/BeanModelUtils.java | 120 ++++++++++
.../internal/beaneditor/PropertyModelImpl.java | 6 +-
.../internal/services/BeanModelSourceImpl.java | 222 +++++++++++++++++++
.../services/PropertyConduitSourceImpl.java | 4 +-
.../tapestry5/services/DataTypeAnalyzer.java | 48 ++++
.../internal/TapestryInternalUtils.java | 8 +-
.../internal/beaneditor/BeanModelUtils.java | 119 ----------
.../internal/services/BeanModelSourceImpl.java | 222 -------------------
.../tapestry5/services/DataTypeAnalyzer.java | 48 ----
.../annotations/UsesMappedConfiguration.java | 41 ----
.../annotations/UsesOrderedConfiguration.java | 33 ---
.../ioc/internal/util/InternalUtils.java | 6 +-
.../annotations/UsesMappedConfiguration.java | 41 ++++
.../annotations/UsesOrderedConfiguration.java | 33 +++
16 files changed, 621 insertions(+), 620 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
deleted file mode 100644
index 08cb88a..0000000
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/BeanModelUtils.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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.internal;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.regex.Pattern;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
-
-/**
- * Some methods broken off tapestry-core's InternalUtils to avoid bringing the whole class
- * plus its multiple dependencies to the BeanModel package.
- */
-public class BeanModelUtils {
-
- public static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
-
- /**
- * @since 5.3
- */
- private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-
-
- /**
- * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
- * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
- * underscore).
- *
- * @param expression a property expression
- * @return the expression with punctuation removed
- */
- public static String extractIdFromPropertyExpression(String expression)
- {
- return replace(expression, NON_WORD_PATTERN, "");
- }
-
- public static String replace(String input, Pattern pattern, String replacement)
- {
- return pattern.matcher(input).replaceAll(replacement);
- }
-
- /**
- * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
- * user presentable form.
- */
- public static String defaultLabel(String id, Messages messages, String propertyExpression)
- {
- String key = id + "-label";
-
- if (messages.contains(key))
- return messages.get(key);
-
- return toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
- }
-
- /**
- * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
- * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
- * following word), thus "user_id" also becomes "User Id".
- */
- public static String toUserPresentable(String id)
- {
- StringBuilder builder = new StringBuilder(id.length() * 2);
-
- char[] chars = id.toCharArray();
- boolean postSpace = true;
- boolean upcaseNext = true;
-
- for (char ch : chars)
- {
- if (upcaseNext)
- {
- builder.append(Character.toUpperCase(ch));
- upcaseNext = false;
-
- continue;
- }
-
- if (ch == '_')
- {
- builder.append(' ');
- upcaseNext = true;
- continue;
- }
-
- boolean upperCase = Character.isUpperCase(ch);
-
- if (upperCase && !postSpace)
- builder.append(' ');
-
- builder.append(ch);
-
- postSpace = upperCase;
- }
-
- return builder.toString();
- }
-
- /**
- * @since 5.3
- */
- public static AnnotationProvider toAnnotationProvider(final Class element)
- {
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationClass.cast(element.getAnnotation(annotationClass));
- }
- };
- }
-
- public static AnnotationProvider toAnnotationProvider(final Method element)
- {
- if (element == null)
- return NULL_ANNOTATION_PROVIDER;
-
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return element.getAnnotation(annotationClass);
- }
- };
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
new file mode 100644
index 0000000..88f4c7f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
@@ -0,0 +1,145 @@
+// 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.internal;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+
+/**
+ * Some methods broken off tapestry-core's InternalUtils to avoid bringing the whole class
+ * plus its multiple dependencies to the BeanModel package.
+ */
+public class InternalBeanModelUtils {
+
+ public static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+ /**
+ * @since 5.3
+ */
+ private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
+
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
new file mode 100644
index 0000000..154ee79
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
@@ -0,0 +1,120 @@
+// 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.beaneditor;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+
+/**
+ * Utilities used in a few places to modify an existing {@link BeanModel}.
+ */
+public final class BeanModelUtils
+{
+
+ final private static String[] EMPTY_STRING_ARRAY = new String[0];
+
+ /**
+ * Performs standard set of modifications to a {@link org.apache.tapestry5.beaneditor.BeanModel}
+ * . First new
+ * properties may be added, then properties removed, then properties reordered.
+ *
+ * @param model to modifiy
+ * @param addPropertyNames comma seperated list of property names to add, or null
+ * @param includePropertyNames comma seperated list of property names to include
+ * @param excludePropertyNames comma seperated list of property names to exclude, or null
+ * @param reorderPropertyNames comma seperated list of property names to reorder, or null
+ */
+ public static void modify(BeanModel model, String addPropertyNames,
+ String includePropertyNames, String excludePropertyNames, String reorderPropertyNames)
+ {
+ if (addPropertyNames != null)
+ add(model, addPropertyNames);
+
+ if (includePropertyNames != null)
+ include(model, join(includePropertyNames, addPropertyNames));
+
+ if (excludePropertyNames != null)
+ exclude(model, excludePropertyNames);
+
+ if (reorderPropertyNames != null)
+ reorder(model, reorderPropertyNames);
+ }
+
+ private static final String join(String firstList, String optionalSecondList)
+ {
+ if (InternalStringUtils.isBlank(optionalSecondList))
+ return firstList;
+
+ return firstList + "," + optionalSecondList;
+ }
+
+ /**
+ * Adds empty properties to the bean model. New properties are added with a <em>null</em>
+ * {@link org.apache.tapestry5.PropertyConduit}. `
+ *
+ * @param model to be modified
+ * @param propertyNames comma-separated list of property names
+ * @see BeanModel#addEmpty(String)
+ */
+ public static void add(BeanModel model, String propertyNames)
+ {
+ for (String name : split(propertyNames))
+ {
+ model.addEmpty(name);
+ }
+ }
+
+ /**
+ * Removes properties from the bean model.
+ *
+ * @param model
+ * @param propertyNames comma-separated list of property names
+ * @see BeanModel#exclude(String...)
+ */
+ public static void exclude(BeanModel model, String propertyNames)
+ {
+ model.exclude(split(propertyNames));
+ }
+
+ /**
+ * Selects a subset of the properties to keep, and reorders them.
+ */
+ public static void include(BeanModel model, String propertyNames)
+ {
+ model.include(split(propertyNames));
+ }
+
+ /**
+ * Reorders properties within the bean model.
+ *
+ * @param model
+ * @param propertyNames comma-separated list of property names
+ * @see BeanModel#reorder(String...)
+ */
+ public static void reorder(BeanModel model, String propertyNames)
+ {
+ model.reorder(split(propertyNames));
+ }
+
+ static String[] split(String propertyNames)
+ {
+ String trimmed = propertyNames.trim();
+
+ if (trimmed.length() == 0)
+ return EMPTY_STRING_ARRAY;
+
+ return trimmed.split("\\s*,\\s*");
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/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
index b21e5bb..4632818 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -20,7 +20,7 @@ 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.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
this.name = name;
this.conduit = conduit;
- id = BeanModelUtils.extractIdFromPropertyExpression(name);
+ id = InternalBeanModelUtils.extractIdFromPropertyExpression(name);
- label = BeanModelUtils.defaultLabel(id, messages, name);
+ label = InternalBeanModelUtils.defaultLabel(id, messages, name);
// TAP5-2305
if (conduit != null)
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
new file mode 100644
index 0000000..bb20de0
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
@@ -0,0 +1,222 @@
+// 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.services;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.beaneditor.NonVisual;
+import org.apache.tapestry5.beaneditor.ReorderProperties;
+import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
+import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.annotations.Primary;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.services.BeanModelSource;
+import org.apache.tapestry5.services.ComponentLayer;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.List;
+
+public class BeanModelSourceImpl implements BeanModelSource
+{
+ private final TypeCoercer typeCoercer;
+
+ private final PropertyAccess propertyAccess;
+
+ private final PropertyConduitSource propertyConduitSource;
+
+ private final PlasticProxyFactory proxyFactory;
+
+ private final DataTypeAnalyzer dataTypeAnalyzer;
+
+ private final ObjectLocator locator;
+
+ private static class PropertyOrder implements Comparable<PropertyOrder>
+ {
+ final String propertyName;
+
+ final int classDepth;
+
+ final int sortKey;
+
+ public PropertyOrder(final String propertyName, int classDepth, int sortKey)
+ {
+ this.propertyName = propertyName;
+ this.classDepth = classDepth;
+ this.sortKey = sortKey;
+ }
+
+ public int compareTo(PropertyOrder o)
+ {
+ int result = classDepth - o.classDepth;
+
+ if (result == 0)
+ result = sortKey - o.sortKey;
+
+ if (result == 0)
+ result = propertyName.compareTo(o.propertyName);
+
+ return result;
+ }
+ }
+
+ /**
+ * @param classAdapter defines the bean that contains the properties
+ * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
+ */
+ private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
+ {
+ List<PropertyOrder> properties = CollectionFactory.newList();
+
+ for (String name : propertyNames)
+ {
+ PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
+
+ Method readMethod = pa.getReadMethod();
+
+ Location location = readMethod == null ? null : proxyFactory.getMethodLocation(readMethod);
+
+ int line = location == null ? -1 : location.getLine();
+
+ properties.add(new PropertyOrder(name, computeDepth(pa), line));
+ }
+
+ Collections.sort(properties);
+
+ propertyNames.clear();
+
+ for (PropertyOrder po : properties)
+ {
+ propertyNames.add(po.propertyName);
+ }
+ }
+
+ private static int computeDepth(PropertyAdapter pa)
+ {
+ int depth = 0;
+ Class c = pa.getDeclaringClass();
+
+ // When the method originates in an interface, the parent may be null, not Object.
+
+ while (c != null && c != Object.class)
+ {
+ depth++;
+ c = c.getSuperclass();
+ }
+
+ return depth;
+ }
+
+ public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
+ PropertyConduitSource propertyConduitSource,
+ @ComponentLayer
+ PlasticProxyFactory proxyFactory,
+ @Primary
+ DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
+ {
+ this.typeCoercer = typeCoercer;
+ this.propertyAccess = propertyAccess;
+ this.propertyConduitSource = propertyConduitSource;
+ this.proxyFactory = proxyFactory;
+ this.dataTypeAnalyzer = dataTypeAnalyzer;
+ this.locator = locator;
+ }
+
+ public <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages)
+ {
+ return create(beanClass, false, messages);
+ }
+
+ public <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages)
+ {
+ return create(beanClass, true, messages);
+ }
+
+ public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
+ {
+ assert beanClass != null;
+ assert messages != null;
+ ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
+
+ BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
+
+ for (final String propertyName : adapter.getPropertyNames())
+ {
+ PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);
+
+ if (!pa.isRead())
+ {
+ continue;
+ }
+
+ if (isStaticFieldProperty(pa))
+ {
+ continue;
+ }
+
+ if (pa.getAnnotation(NonVisual.class) != null)
+ {
+ continue;
+ }
+
+ if (filterReadOnlyProperties && !pa.isUpdate())
+ {
+ continue;
+ }
+
+ final String dataType = dataTypeAnalyzer.identifyDataType(pa);
+
+ // If an unregistered type, then ignore the property.
+
+ if (dataType == null)
+ {
+ continue;
+ }
+
+ model.add(propertyName).dataType(dataType);
+ }
+
+ // First, order the properties based on the location of the getter method
+ // within the class.
+
+ List<String> propertyNames = model.getPropertyNames();
+
+ orderProperties(adapter, propertyNames);
+
+ model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
+
+ // Next, check for an annotation with specific ordering information.
+
+ ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
+
+ if (reorderAnnotation != null)
+ {
+ BeanModelUtils.reorder(model, reorderAnnotation.value());
+ }
+
+ return model;
+ }
+
+ private boolean isStaticFieldProperty(PropertyAdapter adapter)
+ {
+ return adapter.isField() && Modifier.isStatic(adapter.getField().getModifiers());
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 83f67fa..4ce072e 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -19,7 +19,7 @@ import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.Tree;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.internal.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.internal.InternalPropertyConduit;
import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -1260,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
Type returnType = GenericsUtils.extractActualType(activeType, method);
- return new Term(returnType, toUniqueId(method), BeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+ return new Term(returnType, toUniqueId(method), InternalBeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java b/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
new file mode 100644
index 0000000..ba7e995
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
@@ -0,0 +1,48 @@
+// Copyright 2007, 2008, 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.services;
+
+import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
+import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+
+/**
+ * Used by {@link BeanModelSource} to identify the type of data associated with a particular property (represented as a
+ * {@link PropertyAdapter}). The data type is a string used to determine what kind of interface to use for displaying
+ * the value of the property, or what kind of interface to use for editing the value of the property. Common property
+ * types are "text", "enum", "checkbox", but the list is extensible.
+ * <p/>
+ * Different strategies for identifying the data type are encapsulated in the DataTypeAnalyzer service, forming a
+ * chain of command.
+ * <p/>
+ * The DefaultDataTypeAnalyzer service maps property types to data type names.
+ * <p/>
+ * The DataTypeAnalyzer service is an extensible {@linkplain org.apache.tapestry5.ioc.services.ChainBuilder chain of
+ * command}), that (by default) includes {@link org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer} and
+ * the {@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} service (ordered last). It uses an ordered configuration.
+ *
+ * @see org.apache.tapestry5.corelib.components.Grid
+ * @see org.apache.tapestry5.corelib.components.BeanEditForm
+ * @see BeanBlockSource
+ */
+@UsesOrderedConfiguration(DataTypeAnalyzer.class)
+@UsesMappedConfiguration(key = Class.class, value = String.class)
+public interface DataTypeAnalyzer
+{
+ /**
+ * Identifies the data type, if known, or returns null if not known.
+ */
+ String identifyDataType(PropertyAdapter adapter);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index aba7225..e69377f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
*/
public static String toUserPresentable(String id)
{
- return BeanModelUtils.toUserPresentable(id);
+ return InternalBeanModelUtils.toUserPresentable(id);
}
public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
*/
public static String extractIdFromPropertyExpression(String expression)
{
- return BeanModelUtils.extractIdFromPropertyExpression(expression);
+ return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
}
/**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
*/
public static String defaultLabel(String id, Messages messages, String propertyExpression)
{
- return BeanModelUtils.defaultLabel(id, messages, propertyExpression);
+ return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
}
/**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
private static String replace(String input, Pattern pattern, String replacement)
{
- return BeanModelUtils.replace(input, pattern, replacement);
+ return InternalBeanModelUtils.replace(input, pattern, replacement);
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
deleted file mode 100644
index 6a79b6e..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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.beaneditor;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.internal.InternalConstants;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-
-/**
- * Utilities used in a few places to modify an existing {@link BeanModel}.
- */
-public final class BeanModelUtils
-{
-
- /**
- * Performs standard set of modifications to a {@link org.apache.tapestry5.beaneditor.BeanModel}
- * . First new
- * properties may be added, then properties removed, then properties reordered.
- *
- * @param model to modifiy
- * @param addPropertyNames comma seperated list of property names to add, or null
- * @param includePropertyNames comma seperated list of property names to include
- * @param excludePropertyNames comma seperated list of property names to exclude, or null
- * @param reorderPropertyNames comma seperated list of property names to reorder, or null
- */
- public static void modify(BeanModel model, String addPropertyNames,
- String includePropertyNames, String excludePropertyNames, String reorderPropertyNames)
- {
- if (addPropertyNames != null)
- add(model, addPropertyNames);
-
- if (includePropertyNames != null)
- include(model, join(includePropertyNames, addPropertyNames));
-
- if (excludePropertyNames != null)
- exclude(model, excludePropertyNames);
-
- if (reorderPropertyNames != null)
- reorder(model, reorderPropertyNames);
- }
-
- private static final String join(String firstList, String optionalSecondList)
- {
- if (InternalUtils.isBlank(optionalSecondList))
- return firstList;
-
- return firstList + "," + optionalSecondList;
- }
-
- /**
- * Adds empty properties to the bean model. New properties are added with a <em>null</em>
- * {@link org.apache.tapestry5.PropertyConduit}. `
- *
- * @param model to be modified
- * @param propertyNames comma-separated list of property names
- * @see BeanModel#addEmpty(String)
- */
- public static void add(BeanModel model, String propertyNames)
- {
- for (String name : split(propertyNames))
- {
- model.addEmpty(name);
- }
- }
-
- /**
- * Removes properties from the bean model.
- *
- * @param model
- * @param propertyNames comma-separated list of property names
- * @see BeanModel#exclude(String...)
- */
- public static void exclude(BeanModel model, String propertyNames)
- {
- model.exclude(split(propertyNames));
- }
-
- /**
- * Selects a subset of the properties to keep, and reorders them.
- */
- public static void include(BeanModel model, String propertyNames)
- {
- model.include(split(propertyNames));
- }
-
- /**
- * Reorders properties within the bean model.
- *
- * @param model
- * @param propertyNames comma-separated list of property names
- * @see BeanModel#reorder(String...)
- */
- public static void reorder(BeanModel model, String propertyNames)
- {
- model.reorder(split(propertyNames));
- }
-
- static String[] split(String propertyNames)
- {
- String trimmed = propertyNames.trim();
-
- if (trimmed.length() == 0)
- return InternalConstants.EMPTY_STRING_ARRAY;
-
- return trimmed.split("\\s*,\\s*");
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
deleted file mode 100644
index bb20de0..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BeanModelSourceImpl.java
+++ /dev/null
@@ -1,222 +0,0 @@
-// 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.services;
-
-import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.beaneditor.NonVisual;
-import org.apache.tapestry5.beaneditor.ReorderProperties;
-import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
-import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.ObjectLocator;
-import org.apache.tapestry5.ioc.annotations.Primary;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.*;
-import org.apache.tapestry5.services.BeanModelSource;
-import org.apache.tapestry5.services.ComponentLayer;
-import org.apache.tapestry5.services.DataTypeAnalyzer;
-import org.apache.tapestry5.services.PropertyConduitSource;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.List;
-
-public class BeanModelSourceImpl implements BeanModelSource
-{
- private final TypeCoercer typeCoercer;
-
- private final PropertyAccess propertyAccess;
-
- private final PropertyConduitSource propertyConduitSource;
-
- private final PlasticProxyFactory proxyFactory;
-
- private final DataTypeAnalyzer dataTypeAnalyzer;
-
- private final ObjectLocator locator;
-
- private static class PropertyOrder implements Comparable<PropertyOrder>
- {
- final String propertyName;
-
- final int classDepth;
-
- final int sortKey;
-
- public PropertyOrder(final String propertyName, int classDepth, int sortKey)
- {
- this.propertyName = propertyName;
- this.classDepth = classDepth;
- this.sortKey = sortKey;
- }
-
- public int compareTo(PropertyOrder o)
- {
- int result = classDepth - o.classDepth;
-
- if (result == 0)
- result = sortKey - o.sortKey;
-
- if (result == 0)
- result = propertyName.compareTo(o.propertyName);
-
- return result;
- }
- }
-
- /**
- * @param classAdapter defines the bean that contains the properties
- * @param propertyNames the initial set of property names, which will be rebuilt in the correct order
- */
- private void orderProperties(ClassPropertyAdapter classAdapter, List<String> propertyNames)
- {
- List<PropertyOrder> properties = CollectionFactory.newList();
-
- for (String name : propertyNames)
- {
- PropertyAdapter pa = classAdapter.getPropertyAdapter(name);
-
- Method readMethod = pa.getReadMethod();
-
- Location location = readMethod == null ? null : proxyFactory.getMethodLocation(readMethod);
-
- int line = location == null ? -1 : location.getLine();
-
- properties.add(new PropertyOrder(name, computeDepth(pa), line));
- }
-
- Collections.sort(properties);
-
- propertyNames.clear();
-
- for (PropertyOrder po : properties)
- {
- propertyNames.add(po.propertyName);
- }
- }
-
- private static int computeDepth(PropertyAdapter pa)
- {
- int depth = 0;
- Class c = pa.getDeclaringClass();
-
- // When the method originates in an interface, the parent may be null, not Object.
-
- while (c != null && c != Object.class)
- {
- depth++;
- c = c.getSuperclass();
- }
-
- return depth;
- }
-
- public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
- PropertyConduitSource propertyConduitSource,
- @ComponentLayer
- PlasticProxyFactory proxyFactory,
- @Primary
- DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
- {
- this.typeCoercer = typeCoercer;
- this.propertyAccess = propertyAccess;
- this.propertyConduitSource = propertyConduitSource;
- this.proxyFactory = proxyFactory;
- this.dataTypeAnalyzer = dataTypeAnalyzer;
- this.locator = locator;
- }
-
- public <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages)
- {
- return create(beanClass, false, messages);
- }
-
- public <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages)
- {
- return create(beanClass, true, messages);
- }
-
- public <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages)
- {
- assert beanClass != null;
- assert messages != null;
- ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);
-
- BeanModel<T> model = new BeanModelImpl<T>(beanClass, propertyConduitSource, typeCoercer, messages, locator);
-
- for (final String propertyName : adapter.getPropertyNames())
- {
- PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);
-
- if (!pa.isRead())
- {
- continue;
- }
-
- if (isStaticFieldProperty(pa))
- {
- continue;
- }
-
- if (pa.getAnnotation(NonVisual.class) != null)
- {
- continue;
- }
-
- if (filterReadOnlyProperties && !pa.isUpdate())
- {
- continue;
- }
-
- final String dataType = dataTypeAnalyzer.identifyDataType(pa);
-
- // If an unregistered type, then ignore the property.
-
- if (dataType == null)
- {
- continue;
- }
-
- model.add(propertyName).dataType(dataType);
- }
-
- // First, order the properties based on the location of the getter method
- // within the class.
-
- List<String> propertyNames = model.getPropertyNames();
-
- orderProperties(adapter, propertyNames);
-
- model.reorder(propertyNames.toArray(new String[propertyNames.size()]));
-
- // Next, check for an annotation with specific ordering information.
-
- ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);
-
- if (reorderAnnotation != null)
- {
- BeanModelUtils.reorder(model, reorderAnnotation.value());
- }
-
- return model;
- }
-
- private boolean isStaticFieldProperty(PropertyAdapter adapter)
- {
- return adapter.isField() && Modifier.isStatic(adapter.getField().getModifiers());
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
deleted file mode 100644
index ba7e995..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/DataTypeAnalyzer.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2007, 2008, 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.services;
-
-import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
-import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-
-/**
- * Used by {@link BeanModelSource} to identify the type of data associated with a particular property (represented as a
- * {@link PropertyAdapter}). The data type is a string used to determine what kind of interface to use for displaying
- * the value of the property, or what kind of interface to use for editing the value of the property. Common property
- * types are "text", "enum", "checkbox", but the list is extensible.
- * <p/>
- * Different strategies for identifying the data type are encapsulated in the DataTypeAnalyzer service, forming a
- * chain of command.
- * <p/>
- * The DefaultDataTypeAnalyzer service maps property types to data type names.
- * <p/>
- * The DataTypeAnalyzer service is an extensible {@linkplain org.apache.tapestry5.ioc.services.ChainBuilder chain of
- * command}), that (by default) includes {@link org.apache.tapestry5.internal.services.AnnotationDataTypeAnalyzer} and
- * the {@link org.apache.tapestry5.internal.services.DefaultDataTypeAnalyzer} service (ordered last). It uses an ordered configuration.
- *
- * @see org.apache.tapestry5.corelib.components.Grid
- * @see org.apache.tapestry5.corelib.components.BeanEditForm
- * @see BeanBlockSource
- */
-@UsesOrderedConfiguration(DataTypeAnalyzer.class)
-@UsesMappedConfiguration(key = Class.class, value = String.class)
-public interface DataTypeAnalyzer
-{
- /**
- * Identifies the data type, if known, or returns null if not known.
- */
- String identifyDataType(PropertyAdapter adapter);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
deleted file mode 100644
index a336365..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2008, 2009 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.ioc.annotations;
-
-import java.lang.annotation.*;
-
-/**
- * A documentation-only interface placed on service interfaces for services which have a {@linkplain
- * org.apache.tapestry5.ioc.MappedConfiguration mapped configuration}, to identify the type of key (often, a String),
- * and type ofcontribution.
- * <p/>
- * Remember that when the key type is String, the map will be case-insensitive.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesMappedConfiguration
-{
- /**
- * The type of key used to identify contribution values.
- */
- Class key() default String.class;
-
- /**
- * The type of object which may be contributed into the service's configuration.
- */
- Class value();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
deleted file mode 100644
index 7c608f6..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2008, 2009 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.ioc.annotations;
-
-import java.lang.annotation.*;
-
-/**
- * A documentation-only interface placed on service interfaces for services which have an {@linkplain
- * org.apache.tapestry5.ioc.OrderedConfiguration ordered configuration}, to identify the type of contribution.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@Documented
-@UseWith(AnnotationUseContext.SERVICE)
-public @interface UsesOrderedConfiguration
-{
- /**
- * The type of object which may be contributed into the service's configuration.
- */
- Class value();
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
index a40f984..8f1f7b6 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.ioc.internal.util;
import org.apache.tapestry5.func.F;
import org.apache.tapestry5.func.Mapper;
import org.apache.tapestry5.func.Predicate;
-import org.apache.tapestry5.internal.BeanModelUtils;
+import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
import org.apache.tapestry5.ioc.*;
import org.apache.tapestry5.ioc.annotations.*;
@@ -777,7 +777,7 @@ public class InternalUtils
*/
public static AnnotationProvider toAnnotationProvider(final Class element)
{
- return BeanModelUtils.toAnnotationProvider(element);
+ return InternalBeanModelUtils.toAnnotationProvider(element);
}
/**
@@ -1404,7 +1404,7 @@ public class InternalUtils
public static AnnotationProvider toAnnotationProvider(final Method element)
{
- return BeanModelUtils.toAnnotationProvider(element);
+ return InternalBeanModelUtils.toAnnotationProvider(element);
}
public static <T> ObjectCreator<T> createConstructorConstructionPlan(final OperationTracker tracker, final ObjectLocator locator,
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
new file mode 100644
index 0000000..a336365
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesMappedConfiguration.java
@@ -0,0 +1,41 @@
+// Copyright 2008, 2009 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.ioc.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have a {@linkplain
+ * org.apache.tapestry5.ioc.MappedConfiguration mapped configuration}, to identify the type of key (often, a String),
+ * and type ofcontribution.
+ * <p/>
+ * Remember that when the key type is String, the map will be case-insensitive.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesMappedConfiguration
+{
+ /**
+ * The type of key used to identify contribution values.
+ */
+ Class key() default String.class;
+
+ /**
+ * The type of object which may be contributed into the service's configuration.
+ */
+ Class value();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/dd958465/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
new file mode 100644
index 0000000..7c608f6
--- /dev/null
+++ b/tapestry5-annotations/src/main/java/org/apache/tapestry5/ioc/annotations/UsesOrderedConfiguration.java
@@ -0,0 +1,33 @@
+// Copyright 2008, 2009 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.ioc.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * A documentation-only interface placed on service interfaces for services which have an {@linkplain
+ * org.apache.tapestry5.ioc.OrderedConfiguration ordered configuration}, to identify the type of contribution.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@Documented
+@UseWith(AnnotationUseContext.SERVICE)
+public @interface UsesOrderedConfiguration
+{
+ /**
+ * The type of object which may be contributed into the service's configuration.
+ */
+ Class value();
+}
[14/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
Fourth pass creating the BeanModel and Commons packages.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/eb7ec86e
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/eb7ec86e
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/eb7ec86e
Branch: refs/heads/beanmodel-split
Commit: eb7ec86e3368e4a4e20d88c8f009d88fd1d37740
Parents: dd95846
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Sat Dec 6 19:45:14 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Sat Dec 6 19:45:14 2014 -0200
----------------------------------------------------------------------
beanmodel/build.gradle | 1 +
.../beaneditor/BeanModelSourceBuilder.java | 121 +++++
.../internal/InternalBeanModelUtils.java | 145 ------
.../internal/beaneditor/BeanModelImpl.java | 4 +-
.../internal/beaneditor/BeanModelUtils.java | 4 +-
.../internal/beaneditor/PropertyModelImpl.java | 10 +-
.../services/PropertyConduitSourceImpl.java | 10 +-
.../services/ClassPropertyAdapterImpl.java | 249 +++++++++
.../services/PlasticClassListenerLogger.java | 47 ++
.../services/PlasticProxyFactoryImpl.java | 285 +++++++++++
.../internal/services/PropertyAccessImpl.java | 217 ++++++++
.../internal/services/PropertyAdapterImpl.java | 273 ++++++++++
commons/build.gradle | 1 +
.../internal/services/StringInternerImpl.java | 54 ++
.../org/apache/tapestry5/ioc/Configuration.java | 53 ++
.../tapestry5/ioc/MappedConfiguration.java | 81 +++
.../tapestry5/ioc/OrderedConfiguration.java | 84 +++
.../ioc/internal/BasicTypeCoercions.java | 342 +++++++++++++
.../AccessableObjectAnnotationProvider.java | 46 ++
.../services/AnnotationProviderChain.java | 59 +++
.../ioc/internal/services/CompoundCoercion.java | 54 ++
.../ioc/internal/services/ServiceMessages.java | 68 +++
.../ioc/internal/services/StringLocation.java | 65 +++
.../ioc/internal/services/TypeCoercerImpl.java | 508 +++++++++++++++++++
.../ioc/internal/util/InheritanceSearch.java | 159 ++++++
.../ioc/internal/util/InternalCommonsUtils.java | 388 ++++++++++++++
.../ioc/internal/util/InternalStringUtils.java | 203 --------
.../ioc/internal/util/LockSupport.java | 89 ++++
.../ioc/internal/util/MessageFormatterImpl.java | 65 +++
.../ioc/internal/util/MessagesImpl.java | 74 +++
.../ioc/internal/util/TapestryException.java | 23 +-
.../tapestry5/ioc/util/AbstractMessages.java | 94 ++++
.../tapestry5/ioc/util/AvailableValues.java | 4 +-
.../apache/tapestry5/ioc/util/TimeInterval.java | 195 +++++++
.../tapestry5/util/StringToEnumCoercion.java | 91 ++++
.../internal/TapestryInternalUtils.java | 8 +-
.../internal/services/StringInternerImpl.java | 53 --
.../org/apache/tapestry5/ioc/Configuration.java | 53 --
.../tapestry5/ioc/MappedConfiguration.java | 81 ---
.../tapestry5/ioc/OrderedConfiguration.java | 84 ---
.../AccessableObjectAnnotationProvider.java | 46 --
.../services/AnnotationProviderChain.java | 59 ---
.../services/ClassPropertyAdapterImpl.java | 250 ---------
.../ioc/internal/services/CompoundCoercion.java | 54 --
.../services/PlasticClassListenerLogger.java | 47 --
.../services/PlasticProxyFactoryImpl.java | 286 -----------
.../internal/services/PropertyAccessImpl.java | 217 --------
.../internal/services/PropertyAdapterImpl.java | 273 ----------
.../ioc/internal/services/ServiceMessages.java | 68 ---
.../ioc/internal/services/StringLocation.java | 65 ---
.../ioc/internal/services/TypeCoercerImpl.java | 508 -------------------
.../ioc/internal/util/InheritanceSearch.java | 159 ------
.../ioc/internal/util/InternalUtils.java | 138 +++--
.../ioc/internal/util/LockSupport.java | 89 ----
.../ioc/internal/util/MessageFormatterImpl.java | 65 ---
.../ioc/internal/util/MessagesImpl.java | 74 ---
.../ioc/modules/TapestryIOCModule.java | 297 +----------
.../tapestry5/ioc/util/AbstractMessages.java | 94 ----
.../apache/tapestry5/ioc/util/TimeInterval.java | 195 -------
.../tapestry5/util/StringToEnumCoercion.java | 91 ----
60 files changed, 3855 insertions(+), 3665 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/build.gradle
----------------------------------------------------------------------
diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle
index c09ebdd..fba43b7 100644
--- a/beanmodel/build.gradle
+++ b/beanmodel/build.gradle
@@ -26,6 +26,7 @@ dependencies {
compile project(":plastic")
compile project(":tapestry5-annotations")
compile project(":commons")
+ compile "org.slf4j:slf4j-api:${versions.slf4j}"
// Antlr3 tool path used with the antlr3 task
antlr3 "org.antlr:antlr:3.5.2"
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
new file mode 100644
index 0000000..8cef66e
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/beaneditor/BeanModelSourceBuilder.java
@@ -0,0 +1,121 @@
+// Copyright 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.beaneditor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.naming.OperationNotSupportedException;
+
+import org.apache.tapestry5.internal.services.BeanModelSourceImpl;
+import org.apache.tapestry5.internal.services.PropertyConduitSourceImpl;
+import org.apache.tapestry5.internal.services.StringInterner;
+import org.apache.tapestry5.internal.services.StringInternerImpl;
+import org.apache.tapestry5.ioc.Configuration;
+import org.apache.tapestry5.ioc.ObjectLocator;
+import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
+import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
+import org.apache.tapestry5.ioc.internal.services.PropertyAccessImpl;
+import org.apache.tapestry5.ioc.internal.services.TypeCoercerImpl;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.services.BeanModelSource;
+import org.apache.tapestry5.services.DataTypeAnalyzer;
+import org.apache.tapestry5.services.PropertyConduitSource;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for creating {@link BeanModelSource} instances without
+ * Tapestry-IoC. Usage of Tapestry-IoC is still recommended.
+ */
+public class BeanModelSourceBuilder {
+
+ private TypeCoercer typeCoercer;
+ private PropertyAccess propertyAccess;
+ private PropertyConduitSource propertyConduitSource;
+ private PlasticProxyFactory plasticProxyFactory;
+ private DataTypeAnalyzer dataTypeAnalyzer;
+ private ObjectLocator objectLocator;
+ private StringInterner stringInterner;
+
+ /**
+ * Sets the {@link TypeCoercer} to be used.
+ */
+ public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer) {
+ this.typeCoercer = typeCoercer;
+// propertyAccess = new PropertyAcc
+ return this;
+ }
+
+ public BeanModelSource build()
+ {
+
+ if (typeCoercer == null)
+ {
+ createTypeCoercer();
+ }
+
+ if (propertyAccess == null)
+ {
+ propertyAccess = new PropertyAccessImpl();
+ }
+
+ if (stringInterner == null)
+ {
+ stringInterner = new StringInternerImpl();
+ }
+
+ if (plasticProxyFactory == null)
+ {
+ plasticProxyFactory = new PlasticProxyFactoryImpl(getClass().getClassLoader(), LoggerFactory.getLogger(PlasticProxyFactory.class));
+ }
+
+ if (propertyConduitSource == null)
+ {
+ propertyConduitSource = new PropertyConduitSourceImpl(propertyAccess, plasticProxyFactory, typeCoercer, stringInterner);
+ }
+
+ return new BeanModelSourceImpl(typeCoercer, propertyAccess, propertyConduitSource, plasticProxyFactory, dataTypeAnalyzer, objectLocator);
+
+ }
+
+ private void createTypeCoercer() {
+ CoercionTupleConfiguration configuration = new CoercionTupleConfiguration();
+ BasicTypeCoercions.provideBasicTypeCoercions(configuration);
+ typeCoercer = new TypeCoercerImpl(configuration.getTuples());
+ }
+
+ final private static class CoercionTupleConfiguration implements Configuration<CoercionTuple> {
+
+ final private Collection<CoercionTuple> tuples = new ArrayList<CoercionTuple>();
+
+ @Override
+ public void add(CoercionTuple tuble) {
+ tuples.add(tuble);
+ }
+
+ @Override
+ public void addInstance(Class<? extends CoercionTuple> clazz) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ public Collection<CoercionTuple> getTuples() {
+ return tuples;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
deleted file mode 100644
index 88f4c7f..0000000
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/InternalBeanModelUtils.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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.internal;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.regex.Pattern;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
-
-/**
- * Some methods broken off tapestry-core's InternalUtils to avoid bringing the whole class
- * plus its multiple dependencies to the BeanModel package.
- */
-public class InternalBeanModelUtils {
-
- public static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
-
- /**
- * @since 5.3
- */
- private final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
-
-
- /**
- * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
- * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
- * underscore).
- *
- * @param expression a property expression
- * @return the expression with punctuation removed
- */
- public static String extractIdFromPropertyExpression(String expression)
- {
- return replace(expression, NON_WORD_PATTERN, "");
- }
-
- public static String replace(String input, Pattern pattern, String replacement)
- {
- return pattern.matcher(input).replaceAll(replacement);
- }
-
- /**
- * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
- * user presentable form.
- */
- public static String defaultLabel(String id, Messages messages, String propertyExpression)
- {
- String key = id + "-label";
-
- if (messages.contains(key))
- return messages.get(key);
-
- return toUserPresentable(extractIdFromPropertyExpression(InternalStringUtils.lastTerm(propertyExpression)));
- }
-
- /**
- * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
- * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
- * following word), thus "user_id" also becomes "User Id".
- */
- public static String toUserPresentable(String id)
- {
- StringBuilder builder = new StringBuilder(id.length() * 2);
-
- char[] chars = id.toCharArray();
- boolean postSpace = true;
- boolean upcaseNext = true;
-
- for (char ch : chars)
- {
- if (upcaseNext)
- {
- builder.append(Character.toUpperCase(ch));
- upcaseNext = false;
-
- continue;
- }
-
- if (ch == '_')
- {
- builder.append(' ');
- upcaseNext = true;
- continue;
- }
-
- boolean upperCase = Character.isUpperCase(ch);
-
- if (upperCase && !postSpace)
- builder.append(' ');
-
- builder.append(ch);
-
- postSpace = upperCase;
- }
-
- return builder.toString();
- }
-
- /**
- * @since 5.3
- */
- public static AnnotationProvider toAnnotationProvider(final Class element)
- {
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return annotationClass.cast(element.getAnnotation(annotationClass));
- }
- };
- }
-
- public static AnnotationProvider toAnnotationProvider(final Method element)
- {
- if (element == null)
- return NULL_ANNOTATION_PROVIDER;
-
- return new AnnotationProvider()
- {
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return element.getAnnotation(annotationClass);
- }
- };
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/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
index b72a3d6..3b71f0e 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelImpl.java
@@ -22,7 +22,7 @@ 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.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.UnknownValueException;
@@ -93,7 +93,7 @@ public class BeanModelImpl<T> implements BeanModel<T>
private void validateNewPropertyName(String propertyName)
{
- assert InternalStringUtils.isNonBlank(propertyName);
+ assert InternalCommonsUtils.isNonBlank(propertyName);
if (properties.containsKey(propertyName))
throw new RuntimeException(String.format(
"Bean editor model for %s already contains a property model for property '%s'.",
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
index 154ee79..207fb97 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtils.java
@@ -15,7 +15,7 @@
package org.apache.tapestry5.internal.beaneditor;
import org.apache.tapestry5.beaneditor.BeanModel;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
/**
* Utilities used in a few places to modify an existing {@link BeanModel}.
@@ -54,7 +54,7 @@ public final class BeanModelUtils
private static final String join(String firstList, String optionalSecondList)
{
- if (InternalStringUtils.isBlank(optionalSecondList))
+ if (InternalCommonsUtils.isBlank(optionalSecondList))
return firstList;
return firstList + "," + optionalSecondList;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/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
index 4632818..24d0b2d 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/beaneditor/PropertyModelImpl.java
@@ -20,9 +20,9 @@ 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.InternalBeanModelUtils;
import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
import org.apache.tapestry5.plastic.PlasticUtils;
@SuppressWarnings("all")
@@ -48,9 +48,9 @@ public class PropertyModelImpl implements PropertyModel
this.name = name;
this.conduit = conduit;
- id = InternalBeanModelUtils.extractIdFromPropertyExpression(name);
+ id = InternalCommonsUtils.extractIdFromPropertyExpression(name);
- label = InternalBeanModelUtils.defaultLabel(id, messages, name);
+ label = InternalCommonsUtils.defaultLabel(id, messages, name);
// TAP5-2305
if (conduit != null)
@@ -87,7 +87,7 @@ public class PropertyModelImpl implements PropertyModel
public PropertyModel label(String label)
{
- assert InternalStringUtils.isNonBlank(label);
+ assert InternalCommonsUtils.isNonBlank(label);
this.label = label;
return this;
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
index 4ce072e..09d234c 100644
--- a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -19,7 +19,6 @@ import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.tree.Tree;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.PropertyConduit2;
-import org.apache.tapestry5.internal.InternalBeanModelUtils;
import org.apache.tapestry5.internal.InternalPropertyConduit;
import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
@@ -30,7 +29,8 @@ import org.apache.tapestry5.ioc.annotations.PostInjection;
import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
import org.apache.tapestry5.ioc.services.*;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.ExceptionUtils;
@@ -1107,7 +1107,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
- InternalStringUtils.joinSorted(tokenNames));
+ InternalCommonsUtils.joinSorted(tokenNames));
return new RuntimeException(message);
}
@@ -1260,7 +1260,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
Type returnType = GenericsUtils.extractActualType(activeType, method);
- return new Term(returnType, toUniqueId(method), InternalBeanModelUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+ return new Term(returnType, toUniqueId(method), InternalCommonsUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
{
public void doBuild(InstructionBuilder builder)
{
@@ -1364,7 +1364,7 @@ public class PropertyConduitSourceImpl implements PropertyConduitSource
public PropertyConduit create(Class rootClass, String expression)
{
assert rootClass != null;
- assert InternalStringUtils.isNonBlank(expression);
+ assert InternalCommonsUtils.isNonBlank(expression);
MultiKey key = new MultiKey(rootClass, expression);
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
new file mode 100644
index 0000000..5d6dfec
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
@@ -0,0 +1,249 @@
+// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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.ioc.internal.services;
+
+import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
+
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+
+public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
+{
+ private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap();
+
+ private final Class beanType;
+
+ public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> descriptors)
+ {
+ this.beanType = beanType;
+
+ // lazy init
+ Map<String, List<Method>> nonBridgeMethods = null;
+
+ for (PropertyDescriptor pd : descriptors)
+ {
+ // Indexed properties will have a null propertyType (and a non-null
+ // indexedPropertyType). We ignore indexed properties.
+
+ final Class<?> thisPropertyType = pd.getPropertyType();
+ if (thisPropertyType == null)
+ continue;
+
+ Method readMethod = pd.getReadMethod();
+ Method writeMethod = pd.getWriteMethod();
+
+ // TAP5-1493
+ if (readMethod != null && readMethod.isBridge())
+ {
+ if (nonBridgeMethods == null)
+ {
+ nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+ }
+ readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods);
+ }
+
+ // TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed
+ if (readMethod == null) {
+ final String prefix = thisPropertyType != boolean.class ? "get" : "is";
+ try
+ {
+ Method method = beanType.getMethod(prefix + capitalize(pd.getName()));
+ final Class<?> returnType = method.getReturnType();
+ if (returnType.equals(thisPropertyType) || returnType.isInstance(thisPropertyType)) {
+ readMethod = method;
+ }
+ }
+ catch (SecurityException e) {
+ // getter not usable.
+ }
+ catch (NoSuchMethodException e)
+ {
+ // getter doesn't exist.
+ }
+ }
+
+ if (writeMethod != null && writeMethod.isBridge())
+ {
+ if (nonBridgeMethods == null)
+ {
+ nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
+ }
+ writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
+ }
+
+ // TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed
+ if (writeMethod == null) {
+ try
+ {
+ Method method = beanType.getMethod("set" + capitalize(pd.getName()), pd.getPropertyType());
+ final Class<?> returnType = method.getReturnType();
+ if (returnType.equals(void.class)) {
+ writeMethod = method;
+ }
+ }
+ catch (SecurityException e) {
+ // setter not usable.
+ }
+ catch (NoSuchMethodException e)
+ {
+ // setter doesn't exist.
+ }
+ }
+
+ Class propertyType = readMethod == null ? thisPropertyType : GenericsUtils.extractGenericReturnType(
+ beanType, readMethod);
+
+ PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, writeMethod);
+
+ adapters.put(pa.getName(), pa);
+ }
+
+ // Now, add any public fields (even if static) that do not conflict
+
+ for (Field f : beanType.getFields())
+ {
+ String name = f.getName();
+
+ if (!adapters.containsKey(name))
+ {
+ Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f);
+ PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f);
+
+ adapters.put(name, pa);
+ }
+ }
+ }
+
+ private static String capitalize(String name)
+ {
+ return Character.toUpperCase(name.charAt(0)) + name.substring(1);
+ }
+
+ /**
+ * Find a replacement for the method (if one exists)
+ * @param method A method
+ * @param groupedMethods Methods mapped by name
+ * @return A method from groupedMethods with the same name / param count
+ * (default to providedmethod if none found)
+ */
+ private Method findMethodWithSameNameAndParamCount(Method method, Map<String, List<Method>> groupedMethods) {
+ List<Method> methodGroup = groupedMethods.get(method.getName());
+ if (methodGroup != null)
+ {
+ for (Method nonBridgeMethod : methodGroup)
+ {
+ if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length)
+ {
+ // return the non-bridge method with the same name / argument count
+ return nonBridgeMethod;
+ }
+ }
+ }
+
+ // default to the provided method
+ return method;
+ }
+
+ /**
+ * Find all of the public methods that are not bridge methods and
+ * group them by method name
+ *
+ * {@see Method#isBridge()}
+ * @param type Bean type
+ * @return
+ */
+ private Map<String, List<Method>> groupNonBridgeMethodsByName(Class type)
+ {
+ Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap();
+ for (Method method : type.getMethods())
+ {
+ if (!method.isBridge())
+ {
+ List<Method> methodGroup = methodGroupsByName.get(method.getName());
+ if (methodGroup == null)
+ {
+ methodGroup = CollectionFactory.newList();
+ methodGroupsByName.put(method.getName(), methodGroup);
+ }
+ methodGroup.add(method);
+ }
+ }
+ return methodGroupsByName;
+ }
+
+ @Override
+ public Class getBeanType()
+ {
+ return beanType;
+ }
+
+ @Override
+ public String toString()
+ {
+ String names = InternalCommonsUtils.joinSorted(adapters.keySet());
+
+ return String.format("<ClassPropertyAdaptor %s: %s>", beanType.getName(), names);
+ }
+
+ @Override
+ public List<String> getPropertyNames()
+ {
+ return InternalCommonsUtils.sortedKeys(adapters);
+ }
+
+ @Override
+ public PropertyAdapter getPropertyAdapter(String name)
+ {
+ return adapters.get(name);
+ }
+
+ @Override
+ public Object get(Object instance, String propertyName)
+ {
+ return adaptorFor(propertyName).get(instance);
+ }
+
+ @Override
+ public void set(Object instance, String propertyName, Object value)
+ {
+ adaptorFor(propertyName).set(instance, value);
+ }
+
+ @Override
+ public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) {
+ return adaptorFor(propertyName).getAnnotation(annotationClass);
+ }
+
+ private PropertyAdapter adaptorFor(String name)
+ {
+ PropertyAdapter pa = adapters.get(name);
+
+ if (pa == null)
+ throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
+
+ return pa;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
new file mode 100644
index 0000000..8ebdede
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
@@ -0,0 +1,47 @@
+// Copyright 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.ioc.internal.services;
+
+import org.apache.tapestry5.plastic.ClassType;
+import org.apache.tapestry5.plastic.PlasticClassEvent;
+import org.apache.tapestry5.plastic.PlasticClassListener;
+import org.slf4j.Logger;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
+public class PlasticClassListenerLogger implements PlasticClassListener
+{
+ private final Logger logger;
+
+ public PlasticClassListenerLogger(Logger logger)
+ {
+ this.logger = logger;
+ }
+
+ @Override
+ public void classWillLoad(PlasticClassEvent event)
+ {
+ if (logger.isDebugEnabled())
+ {
+ Marker marker = MarkerFactory.getMarker(event.getPrimaryClassName());
+
+ String extendedClassName = event.getType() == ClassType.PRIMARY ? event.getPrimaryClassName() : String
+ .format("%s (%s for %s)", event.getClassName(), event.getType(), event.getPrimaryClassName());
+
+ logger.debug(marker,
+ String.format("Loading class %s:\n%s", extendedClassName, event.getDissasembledBytecode()));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
new file mode 100644
index 0000000..a23ecec
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
@@ -0,0 +1,285 @@
+// Copyright 2011, 2012 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.ioc.internal.services;
+
+import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
+import org.apache.tapestry5.internal.plastic.asm.Type;
+import org.apache.tapestry5.internal.plastic.asm.tree.*;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
+import org.apache.tapestry5.plastic.*;
+import org.slf4j.Logger;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+public class PlasticProxyFactoryImpl implements PlasticProxyFactory
+{
+ public static final String INTERNAL_GET_DELEGATE = "_____internalGetDelegate_DONT_CALL_THIS_METHOD_____";
+
+ private final PlasticManager manager;
+
+ private final Map<String, Location> memberToLocation = CollectionFactory.newConcurrentMap();
+
+ public PlasticProxyFactoryImpl(ClassLoader parentClassLoader, Logger logger)
+ {
+ this(PlasticManager.withClassLoader(parentClassLoader).create(), logger);
+ }
+
+ public PlasticProxyFactoryImpl(PlasticManager manager, Logger logger)
+ {
+ assert manager != null;
+
+ this.manager = manager;
+
+ if (logger != null)
+ {
+ manager.addPlasticClassListener(new PlasticClassListenerLogger(logger));
+ }
+ }
+
+ @Override
+ public ClassLoader getClassLoader()
+ {
+ return manager.getClassLoader();
+ }
+
+ @Override
+ public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback)
+ {
+ return manager.createProxy(interfaceType, implementationType, callback);
+ }
+
+ @Override
+ public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
+ {
+ return manager.createProxy(interfaceType, callback);
+ }
+
+
+ @Override
+ public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType,
+ Class<? extends T> implementationType)
+ {
+ return manager.createProxyTransformation(interfaceType, implementationType);
+ }
+
+ @Override
+ public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType)
+ {
+ return createProxyTransformation(interfaceType, null);
+ }
+
+ @Override
+ public <T> T createProxy(final Class<T> interfaceType, final ObjectCreator<T> creator, final String description)
+ { return createProxy(interfaceType, null, creator, description);
+ }
+
+ @Override
+ public <T> T createProxy(final Class<T> interfaceType, final Class<? extends T> implementationType,
+ final ObjectCreator<T> creator, final String description)
+ {
+ assert creator != null;
+ assert InternalCommonsUtils.isNonBlank(description);
+
+ ClassInstantiator<T> instantiator = createProxy(interfaceType, implementationType, new PlasticClassTransformer()
+ {
+ @Override
+ public void transform(PlasticClass plasticClass)
+ {
+ final PlasticField objectCreatorField = plasticClass.introduceField(ObjectCreator.class, "creator")
+ .inject(creator);
+
+ final String interfaceTypeName = interfaceType.getName();
+ PlasticMethod delegateMethod = plasticClass.introducePrivateMethod(interfaceTypeName, "delegate",
+ null, null);
+
+ final InstructionBuilderCallback returnCreateObject = new InstructionBuilderCallback()
+ {
+ @Override
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadThis().getField(objectCreatorField);
+ builder.invoke(ObjectCreator.class, Object.class, "createObject");
+ builder.checkcast(interfaceType).returnResult();
+ }
+ };
+
+ delegateMethod.changeImplementation(returnCreateObject);
+
+ for (Method method : interfaceType.getMethods())
+ {
+ plasticClass.introduceMethod(method).delegateTo(delegateMethod);
+ }
+
+ // TA5-2235
+ MethodDescription getDelegateMethodDescription =
+ new MethodDescription(interfaceType.getName(), INTERNAL_GET_DELEGATE);
+ plasticClass.introduceMethod(getDelegateMethodDescription, returnCreateObject);
+
+ plasticClass.addToString(description);
+
+ }
+ });
+
+ return interfaceType.cast(instantiator.newInstance());
+ }
+
+ private ClassNode readClassNode(Class clazz)
+ {
+ byte[] bytecode = PlasticInternalUtils.readBytecodeForClass(manager.getClassLoader(), clazz.getName(), false);
+
+ return bytecode == null ? null : PlasticInternalUtils.convertBytecodeToClassNode(bytecode);
+ }
+
+ @Override
+ public Location getMethodLocation(final Method method)
+ {
+ ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
+ {
+ @Override
+ public String createObject()
+ {
+ return InternalCommonsUtils.asString(method);
+ }
+ };
+
+ return getMemberLocation(method, method.getName(), Type.getMethodDescriptor(method),
+ descriptionCreator);
+ }
+
+ @Override
+ public Location getConstructorLocation(final Constructor constructor)
+ {
+ ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
+ {
+ @Override
+ public String createObject()
+ {
+ StringBuilder builder = new StringBuilder(constructor.getDeclaringClass().getName()).append("(");
+ String sep = "";
+
+ for (Class parameterType : constructor.getParameterTypes())
+ {
+ builder.append(sep);
+ builder.append(parameterType.getSimpleName());
+
+ sep = ", ";
+ }
+
+ builder.append(")");
+
+ return builder.toString();
+ }
+ };
+
+ return getMemberLocation(constructor, "<init>", Type.getConstructorDescriptor(constructor),
+ descriptionCreator);
+ }
+
+ @Override
+ public void clearCache()
+ {
+ memberToLocation.clear();
+ }
+
+
+ public Location getMemberLocation(Member member, String methodName, String memberTypeDesc, ObjectCreator<String> textDescriptionCreator)
+ {
+ String className = member.getDeclaringClass().getName();
+
+ String key = className + ":" + methodName + ":" + memberTypeDesc;
+
+ Location location = memberToLocation.get(key);
+
+ if (location == null)
+ {
+ location = constructMemberLocation(member, methodName, memberTypeDesc, textDescriptionCreator.createObject());
+
+ memberToLocation.put(key, location);
+ }
+
+ return location;
+
+ }
+
+ private Location constructMemberLocation(Member member, String methodName, String memberTypeDesc, String textDescription)
+ {
+
+ ClassNode classNode = readClassNode(member.getDeclaringClass());
+
+ if (classNode == null)
+ {
+ throw new RuntimeException(String.format("Unable to read class file for %s (to gather line number information).",
+ textDescription));
+ }
+
+ for (MethodNode mn : (List<MethodNode>) classNode.methods)
+ {
+ if (mn.name.equals(methodName) && mn.desc.equals(memberTypeDesc))
+ {
+ int lineNumber = findFirstLineNumber(mn.instructions);
+
+ // If debugging info is not available, we may lose the line number data, in which case,
+ // just generate the Location from the textDescription.
+
+ if (lineNumber < 1)
+ {
+ break;
+ }
+
+ String description = String.format("%s (at %s:%d)", textDescription, classNode.sourceFile, lineNumber);
+
+ return new StringLocation(description, lineNumber);
+ }
+ }
+
+ // Didn't find it. Odd.
+
+ return new StringLocation(textDescription, 0);
+ }
+
+ private int findFirstLineNumber(InsnList instructions)
+ {
+ for (AbstractInsnNode node = instructions.getFirst(); node != null; node = node.getNext())
+ {
+ if (node instanceof LineNumberNode)
+ {
+ return ((LineNumberNode) node).line;
+ }
+ }
+
+ return -1;
+ }
+
+ @Override
+ public void addPlasticClassListener(PlasticClassListener listener)
+ {
+ manager.addPlasticClassListener(listener);
+ }
+
+ @Override
+ public void removePlasticClassListener(PlasticClassListener listener)
+ {
+ manager.removePlasticClassListener(listener);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
new file mode 100644
index 0000000..8dd1e02
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
@@ -0,0 +1,217 @@
+// Copyright 2006, 2007, 2008, 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.ioc.internal.services;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+
+@SuppressWarnings("unchecked")
+public class PropertyAccessImpl implements PropertyAccess
+{
+ private final Map<Class, ClassPropertyAdapter> adapters = CollectionFactory.newConcurrentMap();
+
+ @Override
+ public Object get(Object instance, String propertyName)
+ {
+ return getAdapter(instance).get(instance, propertyName);
+ }
+
+ @Override
+ public void set(Object instance, String propertyName, Object value)
+ {
+ getAdapter(instance).set(instance, propertyName, value);
+ }
+
+ @Override
+ public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) {
+ return getAdapter(instance).getAnnotation(instance, propertyName, annotationClass);
+ }
+
+
+ /**
+ * Clears the cache of adapters and asks the {@link Introspector} to clear its cache.
+ */
+ @Override
+ public synchronized void clearCache()
+ {
+ adapters.clear();
+
+ Introspector.flushCaches();
+ }
+
+ @Override
+ public ClassPropertyAdapter getAdapter(Object instance)
+ {
+ return getAdapter(instance.getClass());
+ }
+
+ @Override
+ public ClassPropertyAdapter getAdapter(Class forClass)
+ {
+ ClassPropertyAdapter result = adapters.get(forClass);
+
+ if (result == null)
+ {
+ result = buildAdapter(forClass);
+ adapters.put(forClass, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Builds a new adapter and updates the _adapters cache. This not only guards access to the adapter cache, but also
+ * serializes access to the Java Beans Introspector, which is not thread safe. In addition, handles the case where
+ * the class in question is an interface, accumulating properties inherited from super-classes.
+ */
+ private synchronized ClassPropertyAdapter buildAdapter(Class forClass)
+ {
+ // In some race conditions, we may hit this method for the same class multiple times.
+ // We just let it happen, replacing the old ClassPropertyAdapter with a new one.
+
+ try
+ {
+ BeanInfo info = Introspector.getBeanInfo(forClass);
+
+ List<PropertyDescriptor> descriptors = CollectionFactory.newList();
+
+ addAll(descriptors, info.getPropertyDescriptors());
+
+ // TAP5-921 - Introspector misses interface methods not implemented in an abstract class
+ if (forClass.isInterface() || Modifier.isAbstract(forClass.getModifiers()) )
+ addPropertiesFromExtendedInterfaces(forClass, descriptors);
+
+ addPropertiesFromScala(forClass, descriptors);
+
+ return new ClassPropertyAdapterImpl(forClass, descriptors);
+ }
+ catch (Throwable ex)
+ {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private <T> void addAll(List<T> list, T[] array)
+ {
+ list.addAll(Arrays.asList(array));
+ }
+
+ private void addPropertiesFromExtendedInterfaces(Class forClass, List<PropertyDescriptor> descriptors)
+ throws IntrospectionException
+ {
+ LinkedList<Class> queue = CollectionFactory.newLinkedList();
+
+ // Seed the queue
+ addAll(queue, forClass.getInterfaces());
+
+ while (!queue.isEmpty())
+ {
+ Class c = queue.removeFirst();
+
+ BeanInfo info = Introspector.getBeanInfo(c);
+
+ // Duplicates occur and are filtered out in ClassPropertyAdapter which stores
+ // a property name to descriptor map.
+ addAll(descriptors, info.getPropertyDescriptors());
+ addAll(queue, c.getInterfaces());
+ }
+ }
+
+ private void addPropertiesFromScala(Class forClass, List<PropertyDescriptor> descriptors)
+ throws IntrospectionException
+ {
+ for (Method method : forClass.getMethods())
+ {
+ addPropertyIfScalaGetterMethod(forClass, descriptors, method);
+ }
+ }
+
+ private void addPropertyIfScalaGetterMethod(Class forClass, List<PropertyDescriptor> descriptors, Method method)
+ throws IntrospectionException
+ {
+ if (!isScalaGetterMethod(method))
+ return;
+
+ PropertyDescriptor propertyDescriptor = new PropertyDescriptor(method.getName(), forClass, method.getName(),
+ null);
+
+ // found a getter, looking for the setter now
+ try
+ {
+ Method setterMethod = findScalaSetterMethod(forClass, method);
+
+ propertyDescriptor.setWriteMethod(setterMethod);
+ }
+ catch (NoSuchMethodException e)
+ {
+ // ignore
+ }
+
+ // check if the same property was already discovered with java bean accessors
+
+ addScalaPropertyIfNoJavaBeansProperty(descriptors, propertyDescriptor, method);
+ }
+
+ private void addScalaPropertyIfNoJavaBeansProperty(List<PropertyDescriptor> descriptors,
+ PropertyDescriptor propertyDescriptor, Method getterMethod)
+ {
+ boolean found = false;
+
+ for (PropertyDescriptor currentPropertyDescriptor : descriptors)
+ {
+ if (currentPropertyDescriptor.getName().equals(getterMethod.getName()))
+ {
+ found = true;
+
+ break;
+ }
+ }
+
+ if (!found)
+ descriptors.add(propertyDescriptor);
+ }
+
+ private Method findScalaSetterMethod(Class forClass, Method getterMethod) throws NoSuchMethodException
+ {
+ return forClass.getMethod(getterMethod.getName() + "_$eq", getterMethod.getReturnType());
+ }
+
+ private boolean isScalaGetterMethod(Method method)
+ {
+ try
+ {
+ return Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0
+ && !method.getReturnType().equals(Void.TYPE)
+ && method.getDeclaringClass().getDeclaredField(method.getName()) != null;
+ }
+ catch (NoSuchFieldException ex)
+ {
+ return false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
new file mode 100644
index 0000000..97685ef
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
@@ -0,0 +1,273 @@
+// Copyright 2006-2013 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAdapter;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.List;
+
+public class PropertyAdapterImpl implements PropertyAdapter
+{
+ private final ClassPropertyAdapter classAdapter;
+
+ private final String name;
+
+ private final Method readMethod;
+
+ private final Method writeMethod;
+
+ private final Class type;
+
+ private final boolean castRequired;
+
+ // Synchronized by this; lazily initialized
+ private AnnotationProvider annotationProvider;
+
+ private final Field field;
+
+ private final Class declaringClass;
+
+ PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Method readMethod,
+ Method writeMethod)
+ {
+ this.classAdapter = classAdapter;
+ this.name = name;
+ this.type = type;
+
+ this.readMethod = readMethod;
+ this.writeMethod = writeMethod;
+
+ declaringClass = readMethod != null ? readMethod.getDeclaringClass() : writeMethod.getDeclaringClass();
+
+ castRequired = readMethod != null && readMethod.getReturnType() != type;
+
+ field = null;
+ }
+
+ PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Field field)
+ {
+ this.classAdapter = classAdapter;
+ this.name = name;
+ this.type = type;
+
+ this.field = field;
+
+ declaringClass = field.getDeclaringClass();
+
+ castRequired = field.getType() != type;
+
+ readMethod = null;
+ writeMethod = null;
+ }
+
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ @Override
+ public Method getReadMethod()
+ {
+ return readMethod;
+ }
+
+ @Override
+ public Class getType()
+ {
+ return type;
+ }
+
+ @Override
+ public Method getWriteMethod()
+ {
+ return writeMethod;
+ }
+
+ @Override
+ public boolean isRead()
+ {
+ return field != null || readMethod != null;
+ }
+
+ @Override
+ public boolean isUpdate()
+ {
+ return writeMethod != null || (field != null && !isFinal(field));
+ }
+
+ private boolean isFinal(Member member)
+ {
+ return Modifier.isFinal(member.getModifiers());
+ }
+
+ @Override
+ public Object get(Object instance)
+ {
+ if (field == null && readMethod == null)
+ {
+ throw new UnsupportedOperationException(String.format("Class %s does not provide an accessor ('getter') method for property '%s'.", toClassName(instance), name));
+ }
+
+ Throwable fail;
+
+ try
+ {
+ if (field == null)
+ return readMethod.invoke(instance);
+ else
+ return field.get(instance);
+ } catch (InvocationTargetException ex)
+ {
+ fail = ex.getTargetException();
+ } catch (Exception ex)
+ {
+ fail = ex;
+ }
+
+ throw new RuntimeException(ServiceMessages.readFailure(name, instance, fail), fail);
+ }
+
+ @Override
+ public void set(Object instance, Object value)
+ {
+ if (field == null && writeMethod == null)
+ {
+ throw new UnsupportedOperationException(String.format("Class %s does not provide a mutator ('setter') method for property '%s'.",
+ toClassName(instance),
+ name
+ ));
+ }
+
+ Throwable fail;
+
+ try
+ {
+ if (field == null)
+ writeMethod.invoke(instance, value);
+ else
+ field.set(instance, value);
+
+ return;
+ } catch (InvocationTargetException ex)
+ {
+ fail = ex.getTargetException();
+ } catch (Exception ex)
+ {
+ fail = ex;
+ }
+
+ throw new RuntimeException(String.format("Error updating property '%s' of %s: %s",
+ name, toClassName(instance),
+ ExceptionUtils.toMessage(fail)), fail);
+ }
+
+ private String toClassName(Object instance)
+ {
+ return instance == null ? "<null>" : instance.getClass().getName();
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return getAnnnotationProvider().getAnnotation(annotationClass);
+ }
+
+ /**
+ * Creates (as needed) the annotation provider for this property.
+ */
+ private synchronized AnnotationProvider getAnnnotationProvider()
+ {
+ if (annotationProvider == null)
+ {
+ List<AnnotationProvider> providers = CollectionFactory.newList();
+
+ if (readMethod != null)
+ providers.add(new AccessableObjectAnnotationProvider(readMethod));
+
+ if (writeMethod != null)
+ providers.add(new AccessableObjectAnnotationProvider(writeMethod));
+
+ // There's an assumption here, that the fields match the property name (we ignore case
+ // which leads to a manageable ambiguity) and that the field and the getter/setter
+ // are in the same class (i.e., that we don't have a getter exposing a protected field inherted
+ // from a base class, or some other oddity).
+
+ Class cursor = getBeanType();
+
+ out:
+ while (cursor != null)
+ {
+ for (Field f : cursor.getDeclaredFields())
+ {
+ if (f.getName().equalsIgnoreCase(name))
+ {
+ providers.add(new AccessableObjectAnnotationProvider(f));
+
+ break out;
+ }
+ }
+
+ cursor = cursor.getSuperclass();
+ }
+
+ annotationProvider = AnnotationProviderChain.create(providers);
+ }
+
+ return annotationProvider;
+ }
+
+ @Override
+ public boolean isCastRequired()
+ {
+ return castRequired;
+ }
+
+ @Override
+ public ClassPropertyAdapter getClassAdapter()
+ {
+ return classAdapter;
+ }
+
+ @Override
+ public Class getBeanType()
+ {
+ return classAdapter.getBeanType();
+ }
+
+ @Override
+ public boolean isField()
+ {
+ return field != null;
+ }
+
+ @Override
+ public Field getField()
+ {
+ return field;
+ }
+
+ @Override
+ public Class getDeclaringClass()
+ {
+ return declaringClass;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/build.gradle
----------------------------------------------------------------------
diff --git a/commons/build.gradle b/commons/build.gradle
index 76850ef..98ae8bf 100644
--- a/commons/build.gradle
+++ b/commons/build.gradle
@@ -10,6 +10,7 @@ buildDir = 'target/gradle-build'
dependencies {
compile project(":plastic")
compile project(":tapestry5-annotations")
+ compile project(":tapestry-func")
}
jar {
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
new file mode 100644
index 0000000..fae9ab8
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
@@ -0,0 +1,54 @@
+// Copyright 2009, 2012 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 org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.services.ComponentClasses;
+import org.apache.tapestry5.services.InvalidationEventHub;
+
+import javax.annotation.PostConstruct;
+
+import java.util.Map;
+
+public class StringInternerImpl implements StringInterner
+{
+ private final Map<String, String> cache = CollectionFactory.newConcurrentMap();
+
+ @PostConstruct
+ public void setupInvalidation(@ComponentClasses InvalidationEventHub hub)
+ {
+ hub.clearOnInvalidation(cache);
+ }
+
+ public String intern(String string)
+ {
+ String result = cache.get(string);
+
+ // Not yet in the cache? Add it.
+
+ if (result == null)
+ {
+ cache.put(string, string);
+ result = string;
+ }
+
+ return result;
+ }
+
+ public String format(String format, Object... arguments)
+ {
+ return intern(String.format(format, arguments));
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java b/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
new file mode 100644
index 0000000..03814f5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Configuration.java
@@ -0,0 +1,53 @@
+// Copyright 2006, 2008, 2009 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.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * This implementation is used for un-ordered configuration data.
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
+ * must be compatible with the type.
+ */
+public interface Configuration<T>
+{
+ /**
+ * Adds an object to the service's contribution.
+ *
+ * @param object
+ * to add to the service's configuration
+ */
+ void add(T object);
+
+ /**
+ * Automatically instantiates an instance of the class, with dependencies injected, and adds it to the
+ * configuration. When the configuration type is an interface and the class to be contributed is a local file,
+ * then a reloadable proxy for the class will be created and contributed.
+ *
+ * @param clazz
+ * what class to instantiate
+ * @since 5.1.0.0
+ */
+ void addInstance(Class<? extends T> clazz);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java b/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
new file mode 100644
index 0000000..47c6026
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
@@ -0,0 +1,81 @@
+// Copyright 2006, 2008, 2009, 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.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
+ * must be compatible with the type.
+ */
+public interface MappedConfiguration<K, V>
+{
+
+ /**
+ * Adds a keyed object to the service's contribution.
+ *
+ * @param key
+ * unique id for the value
+ * @param value
+ * to contribute
+ * @throws IllegalArgumentException
+ * if key is not unique
+ */
+ void add(K key, V value);
+
+ /**
+ * Overrides an existing contribution by its key.
+ *
+ * @param key
+ * unique id of value to override
+ * @param value
+ * new value, or null to remove the key entirely
+ * @since 5.1.0.0
+ */
+ void override(K key, V value);
+
+ /**
+ * Adds a keyed object as an instantiated instance (with dependencies injected) of a class. When the value
+ * type is an interface and the class to be contributed is a local file,
+ * then a reloadable proxy for the value class will be created and contributed.
+ *
+ * @param key
+ * unique id for the value
+ * @param clazz
+ * class to instantiate and contribute
+ * @since 5.1.0.0
+ */
+ void addInstance(K key, Class<? extends V> clazz);
+
+ /**
+ * Overrides an existing contribution with a new instance. When the value
+ * type is an interface and the class to be contributed is a local file,
+ * then a reloadable proxy for the value class will be created and contributed.
+ *
+ * @param key
+ * unique id of value to override
+ * @param clazz
+ * class to instantiate as override
+ */
+ void overrideInstance(K key, Class<? extends V> clazz);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java b/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
new file mode 100644
index 0000000..9151381
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
@@ -0,0 +1,84 @@
+// Copyright 2006, 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.ioc;
+
+/**
+ * Object passed into a service contributor method that allows the method provide contributed values to the service's
+ * configuration.
+ * <p/>
+ * A service can <em>collect</em> contributions in three different ways:
+ * <ul>
+ * <li>As an un-ordered collection of values</li>
+ * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
+ * <li>As a map of keys and values
+ * </ul>
+ * <p/>
+ * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
+ * must be compatible with the type, or be {@linkplain org.apache.tapestry5.ioc.services.TypeCoercer coercable} to the type.
+ *
+ * @see org.apache.tapestry5.ioc.annotations.Contribute
+ * @see org.apache.tapestry5.ioc.annotations.UsesConfiguration
+ */
+public interface OrderedConfiguration<T>
+{
+ /**
+ * Adds an ordered object to a service's contribution. Each object has an id (which must be unique). Optionally,
+ * pre-requisites (a list of ids that must precede this object) and post-requisites (ids that must follow) can be
+ * provided.
+ * <p/>
+ * <p>If no constraints are supplied, then an implicit constraint is supplied: after the previously
+ * contributed id <em>within the same contribution method</em>.
+ *
+ * @param id a unique id for the object; the id will be fully qualified with the contributing module's id
+ * @param constraints used to order the object relative to other contributed objects
+ * @param object to add to the service's configuration
+ */
+ void add(String id, T object, String... constraints);
+
+ /**
+ * Overrides a normally contributed object. Each override must match a single normally contributed object.
+ *
+ * @param id identifies object to override
+ * @param object overriding object (may be null)
+ * @param constraints constraints for the overridden object, replacing constraints for the original object (even if
+ * omitted, in which case the override object will have no ordering constraints)
+ * @since 5.1.0.0
+ */
+ void override(String id, T object, String... constraints);
+
+ /**
+ * Adds an ordered object by instantiating (with dependencies) the indicated class. When the configuration type is
+ * an interface and the class to be contributed is a local file,
+ * then a reloadable proxy for the class will be created and contributed.
+ *
+ * @param id of contribution (used for ordering)
+ * @param clazz class to instantiate
+ * @param constraints used to order the object relative to other contributed objects
+ * @since 5.1.0.0
+ */
+ void addInstance(String id, Class<? extends T> clazz, String... constraints);
+
+ /**
+ * Instantiates an object and adds it as an override. When the configuration type is an interface and the class to
+ * be contributed is a local file, then a reloadable proxy for the class will be created and contributed.
+ *
+ * @param id of object to override
+ * @param clazz to instantiate
+ * @param constraints constraints for the overridden object, replacing constraints for the original object (even if
+ * omitted, in which case the override object will have no ordering constraints)
+ * @since 5.1.0.0
+ */
+ void overrideInstance(String id, Class<? extends T> clazz, String... constraints);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
new file mode 100644
index 0000000..f7bde31
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/BasicTypeCoercions.java
@@ -0,0 +1,342 @@
+// Copyright 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.ioc.internal;
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.tapestry5.func.Flow;
+import org.apache.tapestry5.ioc.Configuration;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
+import org.apache.tapestry5.ioc.util.TimeInterval;
+
+/**
+ * Class that provides Tapestry-IoC's basic type coercions.
+ * @see TypeCoercer
+ * @see Coercion
+ */
+public class BasicTypeCoercions
+{
+ /**
+ * Provides the basic type coercions to a {@link Configuration} instance.
+ */
+ public static void provideBasicTypeCoercions(Configuration<CoercionTuple> configuration)
+ {
+ add(configuration, Object.class, String.class, new Coercion<Object, String>()
+ {
+ @Override
+ public String coerce(Object input)
+ {
+ return input.toString();
+ }
+ });
+
+ add(configuration, Object.class, Boolean.class, new Coercion<Object, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Object input)
+ {
+ return input != null;
+ }
+ });
+
+ add(configuration, String.class, Double.class, new Coercion<String, Double>()
+ {
+ @Override
+ public Double coerce(String input)
+ {
+ return new Double(input);
+ }
+ });
+
+ // String to BigDecimal is important, as String->Double->BigDecimal would lose
+ // precision.
+
+ add(configuration, String.class, BigDecimal.class, new Coercion<String, BigDecimal>()
+ {
+ @Override
+ public BigDecimal coerce(String input)
+ {
+ return new BigDecimal(input);
+ }
+ });
+
+ add(configuration, BigDecimal.class, Double.class, new Coercion<BigDecimal, Double>()
+ {
+ @Override
+ public Double coerce(BigDecimal input)
+ {
+ return input.doubleValue();
+ }
+ });
+
+ add(configuration, String.class, BigInteger.class, new Coercion<String, BigInteger>()
+ {
+ @Override
+ public BigInteger coerce(String input)
+ {
+ return new BigInteger(input);
+ }
+ });
+
+ add(configuration, String.class, Long.class, new Coercion<String, Long>()
+ {
+ @Override
+ public Long coerce(String input)
+ {
+ return new Long(input);
+ }
+ });
+
+ add(configuration, Long.class, Byte.class, new Coercion<Long, Byte>()
+ {
+ @Override
+ public Byte coerce(Long input)
+ {
+ return input.byteValue();
+ }
+ });
+
+ add(configuration, Long.class, Short.class, new Coercion<Long, Short>()
+ {
+ @Override
+ public Short coerce(Long input)
+ {
+ return input.shortValue();
+ }
+ });
+
+ add(configuration, Long.class, Integer.class, new Coercion<Long, Integer>()
+ {
+ @Override
+ public Integer coerce(Long input)
+ {
+ return input.intValue();
+ }
+ });
+
+ add(configuration, Number.class, Long.class, new Coercion<Number, Long>()
+ {
+ @Override
+ public Long coerce(Number input)
+ {
+ return input.longValue();
+ }
+ });
+
+ add(configuration, Double.class, Float.class, new Coercion<Double, Float>()
+ {
+ @Override
+ public Float coerce(Double input)
+ {
+ return input.floatValue();
+ }
+ });
+
+ add(configuration, Long.class, Double.class, new Coercion<Long, Double>()
+ {
+ @Override
+ public Double coerce(Long input)
+ {
+ return input.doubleValue();
+ }
+ });
+
+ add(configuration, String.class, Boolean.class, new Coercion<String, Boolean>()
+ {
+ @Override
+ public Boolean coerce(String input)
+ {
+ String trimmed = input == null ? "" : input.trim();
+
+ if (trimmed.equalsIgnoreCase("false") || trimmed.length() == 0)
+ return false;
+
+ // Any non-blank string but "false"
+
+ return true;
+ }
+ });
+
+ add(configuration, Number.class, Boolean.class, new Coercion<Number, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Number input)
+ {
+ return input.longValue() != 0;
+ }
+ });
+
+ add(configuration, Void.class, Boolean.class, new Coercion<Void, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Void input)
+ {
+ return false;
+ }
+ });
+
+ add(configuration, Collection.class, Boolean.class, new Coercion<Collection, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Collection input)
+ {
+ return !input.isEmpty();
+ }
+ });
+
+ add(configuration, Object.class, List.class, new Coercion<Object, List>()
+ {
+ @Override
+ public List coerce(Object input)
+ {
+ return Collections.singletonList(input);
+ }
+ });
+
+ add(configuration, Object[].class, List.class, new Coercion<Object[], List>()
+ {
+ @Override
+ public List coerce(Object[] input)
+ {
+ return Arrays.asList(input);
+ }
+ });
+
+ add(configuration, Object[].class, Boolean.class, new Coercion<Object[], Boolean>()
+ {
+ @Override
+ public Boolean coerce(Object[] input)
+ {
+ return input != null && input.length > 0;
+ }
+ });
+
+ add(configuration, Float.class, Double.class, new Coercion<Float, Double>()
+ {
+ @Override
+ public Double coerce(Float input)
+ {
+ return input.doubleValue();
+ }
+ });
+
+ Coercion primitiveArrayCoercion = new Coercion<Object, List>()
+ {
+ @Override
+ public List<Object> coerce(Object input)
+ {
+ int length = Array.getLength(input);
+ Object[] array = new Object[length];
+ for (int i = 0; i < length; i++)
+ {
+ array[i] = Array.get(input, i);
+ }
+ return Arrays.asList(array);
+ }
+ };
+
+ add(configuration, byte[].class, List.class, primitiveArrayCoercion);
+ add(configuration, short[].class, List.class, primitiveArrayCoercion);
+ add(configuration, int[].class, List.class, primitiveArrayCoercion);
+ add(configuration, long[].class, List.class, primitiveArrayCoercion);
+ add(configuration, float[].class, List.class, primitiveArrayCoercion);
+ add(configuration, double[].class, List.class, primitiveArrayCoercion);
+ add(configuration, char[].class, List.class, primitiveArrayCoercion);
+ add(configuration, boolean[].class, List.class, primitiveArrayCoercion);
+
+ add(configuration, String.class, File.class, new Coercion<String, File>()
+ {
+ @Override
+ public File coerce(String input)
+ {
+ return new File(input);
+ }
+ });
+
+ add(configuration, String.class, TimeInterval.class, new Coercion<String, TimeInterval>()
+ {
+ @Override
+ public TimeInterval coerce(String input)
+ {
+ return new TimeInterval(input);
+ }
+ });
+
+ add(configuration, TimeInterval.class, Long.class, new Coercion<TimeInterval, Long>()
+ {
+ @Override
+ public Long coerce(TimeInterval input)
+ {
+ return input.milliseconds();
+ }
+ });
+
+ add(configuration, Object.class, Object[].class, new Coercion<Object, Object[]>()
+ {
+ @Override
+ public Object[] coerce(Object input)
+ {
+ return new Object[]
+ {input};
+ }
+ });
+
+ add(configuration, Collection.class, Object[].class, new Coercion<Collection, Object[]>()
+ {
+ @Override
+ public Object[] coerce(Collection input)
+ {
+ return input.toArray();
+ }
+ });
+
+ configuration.add(CoercionTuple.create(Flow.class, List.class, new Coercion<Flow, List>()
+ {
+ @Override
+ public List coerce(Flow input)
+ {
+ return input.toList();
+ }
+ }));
+
+ configuration.add(CoercionTuple.create(Flow.class, Boolean.class, new Coercion<Flow, Boolean>()
+ {
+ @Override
+ public Boolean coerce(Flow input)
+ {
+ return !input.isEmpty();
+ }
+ }));
+
+
+ }
+
+ private static <S, T> void add(Configuration<CoercionTuple> configuration, Class<S> sourceType,
+ Class<T> targetType, Coercion<S, T> coercion)
+ {
+ configuration.add(CoercionTuple.create(sourceType, targetType, coercion));
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
new file mode 100644
index 0000000..2acfd0d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
@@ -0,0 +1,46 @@
+// Copyright 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+
+/**
+ * Provides access to annotations of an accessable object such as a {@link java.lang.reflect.Method} or {@link
+ * java.lang.reflect.Field}.
+ */
+public class AccessableObjectAnnotationProvider implements AnnotationProvider
+{
+ private final AccessibleObject object;
+
+ public AccessableObjectAnnotationProvider(AccessibleObject object)
+ {
+ this.object = object;
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return object.getAnnotation(annotationClass);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("AnnotationProvider[%s]", object);
+ }
+}
[13/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
new file mode 100644
index 0000000..49b0b15
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
@@ -0,0 +1,59 @@
+// Copyright 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+/**
+ * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
+ */
+public class AnnotationProviderChain implements AnnotationProvider
+{
+ private final AnnotationProvider[] providers;
+
+ public AnnotationProviderChain(AnnotationProvider[] providers)
+ {
+ this.providers = providers;
+ }
+
+ /**
+ * Creates an AnnotationProvider from the list of providers. Returns either an {@link AnnotationProviderChain} or
+ * the sole element in the list.
+ */
+ public static AnnotationProvider create(List<AnnotationProvider> providers)
+ {
+ int size = providers.size();
+
+ if (size == 1) return providers.get(0);
+
+ return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ for (AnnotationProvider p : providers)
+ {
+ T result = p.getAnnotation(annotationClass);
+
+ if (result != null) return result;
+ }
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
new file mode 100644
index 0000000..4a5dece
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
@@ -0,0 +1,54 @@
+// Copyright 2006, 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.services.Coercion;
+
+/**
+ * Combines two coercions to create a coercion through an intermediate type.
+ *
+ * @param <S> The source (input) type
+ * @param <I> The intermediate type
+ * @param <T> The target (output) type
+ */
+public class CompoundCoercion<S, I, T> implements Coercion<S, T>
+{
+ private final Coercion<S, I> op1;
+
+ private final Coercion<I, T> op2;
+
+ public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
+ {
+ this.op1 = op1;
+ this.op2 = op2;
+ }
+
+ @Override
+ public T coerce(S input)
+ {
+ // Run the input through the first operation (S --> I), then run the result of that through
+ // the second operation (I --> T).
+
+ I intermediate = op1.coerce(input);
+
+ return op2.coerce(intermediate);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s, %s", op1, op2);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
new file mode 100644
index 0000000..e92ef2d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
@@ -0,0 +1,68 @@
+// Copyright 2006, 2007, 2011, 2012 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+public class ServiceMessages
+{
+ private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
+
+ private ServiceMessages()
+ {
+ }
+
+ public static String noSuchProperty(Class clazz, String propertyName)
+ {
+ return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
+ }
+
+
+ public static String readFailure(String propertyName, Object instance, Throwable cause)
+ {
+ return MESSAGES.format("read-failure", propertyName, instance, cause);
+ }
+
+ public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
+ Class expectedType)
+ {
+ return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
+ expectedType.getName());
+ }
+
+ public static String shutdownListenerError(Object listener, Throwable cause)
+ {
+ return MESSAGES.format("shutdown-listener-error", listener, cause);
+ }
+
+ public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
+ {
+ return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
+ coercion, cause);
+ }
+
+ public static String registryShutdown(String serviceId)
+ {
+ return MESSAGES.format("registry-shutdown", serviceId);
+ }
+
+ public static String serviceBuildFailure(String serviceId, Throwable cause)
+ {
+ return MESSAGES.format("service-build-failure", serviceId, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
new file mode 100644
index 0000000..0769b7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
@@ -0,0 +1,65 @@
+// 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.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Resource;
+
+/**
+ * Implementation of {@link Location} used when the underlying resource isn't really known.
+ */
+public final class StringLocation implements Location
+{
+ private final String description;
+
+ private final int line;
+
+ public StringLocation(String description, int line)
+ {
+ this.description = description;
+ this.line = line;
+ }
+
+ @Override
+ public String toString()
+ {
+ return description;
+ }
+
+ /**
+ * Returns 0.
+ */
+ @Override
+ public int getColumn()
+ {
+ return 0;
+ }
+
+ @Override
+ public int getLine()
+ {
+ return line;
+ }
+
+ /**
+ * Returns null; we don't know where the file really is (it's probably a class on the class path).
+ */
+ @Override
+ public Resource getResource()
+ {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
new file mode 100644
index 0000000..6481384
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
@@ -0,0 +1,508 @@
+// Copyright 2006, 2007, 2008, 2010, 2012 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.ioc.internal.services;
+
+import org.apache.tapestry5.func.F;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.internal.util.LockSupport;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.services.CoercionTuple;
+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.util.StringToEnumCoercion;
+
+import java.util.*;
+
+@SuppressWarnings("all")
+public class TypeCoercerImpl extends LockSupport implements TypeCoercer
+{
+ // Constructed from the service's configuration.
+
+ private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
+
+ /**
+ * A coercion to a specific target type. Manages a cache of coercions to specific types.
+ */
+ private class TargetCoercion
+ {
+ private final Class type;
+
+ private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
+
+ TargetCoercion(Class type)
+ {
+ this.type = type;
+ }
+
+ void clearCache()
+ {
+ cache.clear();
+ }
+
+ Object coerce(Object input)
+ {
+ Class sourceType = input != null ? input.getClass() : Void.class;
+
+ if (type.isAssignableFrom(sourceType))
+ {
+ return input;
+ }
+
+ Coercion c = getCoercion(sourceType);
+
+ try
+ {
+ return type.cast(c.coerce(input));
+ } catch (Exception ex)
+ {
+ throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
+ }
+ }
+
+ String explain(Class sourceType)
+ {
+ return getCoercion(sourceType).toString();
+ }
+
+ private Coercion getCoercion(Class sourceType)
+ {
+ Coercion c = cache.get(sourceType);
+
+ if (c == null)
+ {
+ c = findOrCreateCoercion(sourceType, type);
+ cache.put(sourceType, c);
+ }
+
+ return c;
+ }
+ }
+
+ /**
+ * Map from a target type to a TargetCoercion for that type.
+ */
+ private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
+
+ private static final Coercion NO_COERCION = new Coercion<Object, Object>()
+ {
+ @Override
+ public Object coerce(Object input)
+ {
+ return input;
+ }
+ };
+
+ private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
+ {
+ @Override
+ public Object coerce(Void input)
+ {
+ return null;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "null --> null";
+ }
+ };
+
+ public TypeCoercerImpl(Collection<CoercionTuple> tuples)
+ {
+ for (CoercionTuple tuple : tuples)
+ {
+ Class key = tuple.getSourceType();
+
+ InternalCommonsUtils.addToMapList(sourceTypeToTuple, key, tuple);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object coerce(Object input, Class targetType)
+ {
+ assert targetType != null;
+
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+ if (effectiveTargetType.isInstance(input))
+ {
+ return input;
+ }
+
+
+ return getTargetCoercion(effectiveTargetType).coerce(input);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
+ {
+ assert sourceType != null;
+ assert targetType != null;
+
+ Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+
+ if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+ {
+ return NO_COERCION;
+ }
+
+ return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
+ {
+ assert sourceType != null;
+ assert targetType != null;
+
+ Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
+ Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
+
+ // Is a coercion even necessary? Not if the target type is assignable from the
+ // input value.
+
+ if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
+ {
+ return "";
+ }
+
+ return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
+ }
+
+ private TargetCoercion getTargetCoercion(Class targetType)
+ {
+ try
+ {
+ acquireReadLock();
+
+ TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+ return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
+ } finally
+ {
+ releaseReadLock();
+ }
+ }
+
+ private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
+ {
+ try
+ {
+ upgradeReadLockToWriteLock();
+
+ // Inner check since some other thread may have beat us to it.
+
+ TargetCoercion tc = typeToTargetCoercion.get(targetType);
+
+ if (tc == null)
+ {
+ tc = new TargetCoercion(targetType);
+ typeToTargetCoercion.put(targetType, tc);
+ }
+
+ return tc;
+ } finally
+ {
+ downgradeWriteLockToReadLock();
+ }
+ }
+
+ @Override
+ public void clearCache()
+ {
+ try
+ {
+ acquireReadLock();
+
+ // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
+ // will release the keys for classes that are no longer in existence. On the other hand,
+ // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
+ // individual cache, so clear all those.
+
+ for (TargetCoercion tc : typeToTargetCoercion.values())
+ {
+ // Can tc ever be null?
+
+ tc.clearCache();
+ }
+ } finally
+ {
+ releaseReadLock();
+ }
+ }
+
+ /**
+ * Here's the real meat; we do a search of the space to find coercions, or a system of
+ * coercions, that accomplish
+ * the desired coercion.
+ * <p/>
+ * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
+ * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
+ * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
+ * <p/>
+ * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
+ * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
+ * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
+ * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
+ * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
+ * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
+ * final response.
+ * <p/>
+ * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
+ * really good at.
+ *
+ * @param sourceType
+ * @param targetType
+ * @return coercer from sourceType to targetType
+ */
+ @SuppressWarnings("unchecked")
+ private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
+ {
+ if (sourceType == Void.class)
+ {
+ return searchForNullCoercion(targetType);
+ }
+
+ // These are instance variables because this method may be called concurrently.
+ // On a true race, we may go to the work of seeking out and/or fabricating
+ // a tuple twice, but it's more likely that different threads are looking
+ // for different source/target coercions.
+
+ Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
+ LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
+
+ seedQueue(sourceType, targetType, consideredTuples, queue);
+
+ while (!queue.isEmpty())
+ {
+ CoercionTuple tuple = queue.removeFirst();
+
+ // If the tuple results in a value type that is assignable to the desired target type,
+ // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
+ // "quality" (how close is the tuple target type to the desired target type). Cost
+ // is currently implicit, as compound tuples are stored deeper in the queue,
+ // so simpler coercions will be located earlier.
+
+ Class tupleTargetType = tuple.getTargetType();
+
+ if (targetType.isAssignableFrom(tupleTargetType))
+ {
+ return tuple.getCoercion();
+ }
+
+ // So .. this tuple doesn't get us directly to the target type.
+ // However, it *may* get us part of the way. Each of these
+ // represents a coercion from the source type to an intermediate type.
+ // Now we're going to look for conversions from the intermediate type
+ // to some other type.
+
+ queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
+ }
+
+ // Not found anywhere. Identify the source and target type and a (sorted) list of
+ // all the known coercions.
+
+ throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
+ sourceType.getName(), targetType.getName()), buildCoercionCatalog());
+ }
+
+ /**
+ * Coercion from null is special; we match based on the target type and its not a spanning
+ * search. In many cases, we
+ * return a pass-thru that leaves the value as null.
+ *
+ * @param targetType
+ * desired type
+ * @return the coercion
+ */
+ private Coercion searchForNullCoercion(Class targetType)
+ {
+ List<CoercionTuple> tuples = getTuples(Void.class, targetType);
+
+ for (CoercionTuple tuple : tuples)
+ {
+ Class tupleTargetType = tuple.getTargetType();
+
+ if (targetType.equals(tupleTargetType))
+ return tuple.getCoercion();
+ }
+
+ // Typical case: no match, this coercion passes the null through
+ // as null.
+
+ return COERCION_NULL_TO_OBJECT;
+ }
+
+ /**
+ * Builds a string listing all the coercions configured for the type coercer, sorted
+ * alphabetically.
+ */
+ @SuppressWarnings("unchecked")
+ private AvailableValues buildCoercionCatalog()
+ {
+ List<CoercionTuple> masterList = CollectionFactory.newList();
+
+ for (List<CoercionTuple> list : sourceTypeToTuple.values())
+ {
+ masterList.addAll(list);
+ }
+
+ return new AvailableValues("Configured coercions", masterList);
+ }
+
+ /**
+ * Seeds the pool with the initial set of coercions for the given type.
+ */
+ private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
+ LinkedList<CoercionTuple> queue)
+ {
+ // Work from the source type up looking for tuples
+
+ for (Class c : new InheritanceSearch(sourceType))
+ {
+ List<CoercionTuple> tuples = getTuples(c, targetType);
+
+ if (tuples == null)
+ {
+ continue;
+ }
+
+ for (CoercionTuple tuple : tuples)
+ {
+ queue.addLast(tuple);
+ consideredTuples.add(tuple);
+ }
+
+ // Don't pull in Object -> type coercions when doing
+ // a search from null.
+
+ if (sourceType == Void.class)
+ {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
+ * compound coercion tuples
+ * to the end of the queue.
+ *
+ * @param sourceType
+ * the source type of the coercion
+ * @param targetType
+ * TODO
+ * @param intermediateTuple
+ * a tuple that converts from the source type to some intermediate type (that is not
+ * assignable to the target type)
+ * @param consideredTuples
+ * set of tuples that have already been added to the pool (directly, or as a compound
+ * coercion)
+ * @param queue
+ * the work queue of tuples
+ */
+ @SuppressWarnings("unchecked")
+ private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
+ Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
+ {
+ Class intermediateType = intermediateTuple.getTargetType();
+
+ for (Class c : new InheritanceSearch(intermediateType))
+ {
+ for (CoercionTuple tuple : getTuples(c, targetType))
+ {
+ if (consideredTuples.contains(tuple))
+ {
+ continue;
+ }
+
+ Class newIntermediateType = tuple.getTargetType();
+
+ // If this tuple is for coercing from an intermediate type back towards our
+ // initial source type, then ignore it. This should only be an optimization,
+ // as branches that loop back towards the source type will
+ // eventually be considered and discarded.
+
+ if (sourceType.isAssignableFrom(newIntermediateType))
+ {
+ continue;
+ }
+
+ // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
+ // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
+ // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
+ // intermediate type, hopefully closer to our eventual target type.
+
+ Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
+
+ CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
+
+ // So, every tuple that is added to the queue can take as input the sourceType.
+ // The target type may be another intermediate type, or may be something
+ // assignable to the target type, which will bring the search to a successful
+ // conclusion.
+
+ queue.addLast(compoundTuple);
+ consideredTuples.add(tuple);
+ }
+ }
+ }
+
+ /**
+ * Returns a non-null list of the tuples from the source type.
+ *
+ * @param sourceType
+ * used to locate tuples
+ * @param targetType
+ * used to add synthetic tuples
+ * @return non-null list of tuples
+ */
+ private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
+ {
+ List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
+
+ if (tuples == null)
+ {
+ tuples = Collections.emptyList();
+ }
+
+ // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
+ // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
+ // safe way (i.e., what if the Enum is defined by a class loader that gets discarded? Don't want to cause
+ // memory leaks by retaining an instance). In any case, there are edge cases where we may create
+ // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
+ // configuration), but on the whole, this is cheap and works.
+
+ if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
+ {
+ tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
+ }
+
+ return tuples;
+ }
+
+ private static <T> List<T> extend(List<T> list, T extraValue)
+ {
+ return F.flow(list).append(extraValue).toList();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
new file mode 100644
index 0000000..f1830a7
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
@@ -0,0 +1,159 @@
+// Copyright 2006 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.ioc.internal.util;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+/**
+ * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
+ * <p/>
+ * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
+ * skips java.lang.Object.
+ * <p/>
+ * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
+ * interfaces implemented by the initial class at its super classes.
+ * <p/>
+ * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
+ * <p/>
+ * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
+ * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
+ * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
+ * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
+ * <p/>
+ * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
+ * search : new InheritanceSearch(startClass)) { ... } </code>
+ * <p/>
+ * This class is not thread-safe.
+ */
+public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
+{
+ private Class searchClass;
+
+ private final Set<Class> addedInterfaces = CollectionFactory.newSet();
+
+ private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
+
+ private enum State
+ {
+ CLASS, INTERFACE, DONE
+ }
+
+ private State state;
+
+ public InheritanceSearch(Class searchClass)
+ {
+ this.searchClass = searchClass;
+
+ queueInterfaces(searchClass);
+
+ state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
+ }
+
+ private void queueInterfaces(Class searchClass)
+ {
+ for (Class intf : searchClass.getInterfaces())
+ {
+ if (addedInterfaces.contains(intf)) continue;
+
+ interfaceQueue.addLast(intf);
+ addedInterfaces.add(intf);
+ }
+ }
+
+ @Override
+ public Iterator<Class> iterator()
+ {
+ return this;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return state != State.DONE;
+ }
+
+ @Override
+ public Class next()
+ {
+ switch (state)
+ {
+ case CLASS:
+
+ Class result = searchClass;
+
+ searchClass = parentOf(searchClass);
+
+ if (searchClass == null) state = State.INTERFACE;
+ else queueInterfaces(searchClass);
+
+ return result;
+
+ case INTERFACE:
+
+ if (interfaceQueue.isEmpty())
+ {
+ state = State.DONE;
+ return Object.class;
+ }
+
+ Class intf = interfaceQueue.removeFirst();
+
+ queueInterfaces(intf);
+
+ return intf;
+
+ default:
+ throw new IllegalStateException();
+ }
+
+ }
+
+ /**
+ * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
+ * Object.class.
+ */
+ private Class parentOf(Class clazz)
+ {
+ if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
+
+ if (clazz.isArray() && clazz != Object[].class)
+ {
+ Class componentType = clazz.getComponentType();
+
+ while (componentType.isArray()) componentType = componentType.getComponentType();
+
+ if (!componentType.isPrimitive()) return Object[].class;
+ }
+
+ Class parent = clazz.getSuperclass();
+
+ return parent != Object.class ? parent : null;
+ }
+
+ /**
+ * @throws UnsupportedOperationException
+ * always
+ */
+ @Override
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
new file mode 100644
index 0000000..3c391e0
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalCommonsUtils.java
@@ -0,0 +1,388 @@
+// Copyright 2006-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.ioc.internal.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+
+/**
+ * Utility methods class for the Commons package.
+ */
+public class InternalCommonsUtils {
+
+ /**
+ * @since 5.3
+ */
+ public final static AnnotationProvider NULL_ANNOTATION_PROVIDER = new NullAnnotationProvider();
+ private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
+
+ /**
+ * Adds a value to a specially organized map where the values are lists of objects. This somewhat simulates a map
+ * that allows multiple values for the same key.
+ *
+ * @param map
+ * to store value into
+ * @param key
+ * for which a value is added
+ * @param value
+ * to add
+ * @param <K>
+ * the type of key
+ * @param <V>
+ * the type of the list
+ */
+ public static <K, V> void addToMapList(Map<K, List<V>> map, K key, V value)
+ {
+ List<V> list = map.get(key);
+
+ if (list == null)
+ {
+ list = CollectionFactory.newList();
+ map.put(key, list);
+ }
+
+ list.add(value);
+ }
+
+ /**
+ * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
+ * convertable to a location.
+ */
+
+ public static Location locationOf(Object location)
+ {
+ if (location == null)
+ return null;
+
+ if (location instanceof Location)
+ return (Location) location;
+
+ if (location instanceof Locatable)
+ return ((Locatable) location).getLocation();
+
+ return null;
+ }
+
+ public static AnnotationProvider toAnnotationProvider(final Method element)
+ {
+ if (element == null)
+ return NULL_ANNOTATION_PROVIDER;
+
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return element.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+ /**
+ * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
+ * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
+ * underscore).
+ *
+ * @param expression a property expression
+ * @return the expression with punctuation removed
+ */
+ public static String extractIdFromPropertyExpression(String expression)
+ {
+ return replace(expression, NON_WORD_PATTERN, "");
+ }
+
+ public static String replace(String input, Pattern pattern, String replacement)
+ {
+ return pattern.matcher(input).replaceAll(replacement);
+ }
+
+ /**
+ * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
+ * user presentable form.
+ */
+ public static String defaultLabel(String id, Messages messages, String propertyExpression)
+ {
+ String key = id + "-label";
+
+ if (messages.contains(key))
+ return messages.get(key);
+
+ return toUserPresentable(extractIdFromPropertyExpression(InternalCommonsUtils.lastTerm(propertyExpression)));
+ }
+
+ /**
+ * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
+ * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
+ * following word), thus "user_id" also becomes "User Id".
+ */
+ public static String toUserPresentable(String id)
+ {
+ StringBuilder builder = new StringBuilder(id.length() * 2);
+
+ char[] chars = id.toCharArray();
+ boolean postSpace = true;
+ boolean upcaseNext = true;
+
+ for (char ch : chars)
+ {
+ if (upcaseNext)
+ {
+ builder.append(Character.toUpperCase(ch));
+ upcaseNext = false;
+
+ continue;
+ }
+
+ if (ch == '_')
+ {
+ builder.append(' ');
+ upcaseNext = true;
+ continue;
+ }
+
+ boolean upperCase = Character.isUpperCase(ch);
+
+ if (upperCase && !postSpace)
+ builder.append(' ');
+
+ builder.append(ch);
+
+ postSpace = upperCase;
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * @since 5.3
+ */
+ public static AnnotationProvider toAnnotationProvider(final Class element)
+ {
+ return new AnnotationProvider()
+ {
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return annotationClass.cast(element.getAnnotation(annotationClass));
+ }
+ };
+ }
+
+ /**
+ * Pattern used to eliminate leading and trailing underscores and dollar signs.
+ */
+ static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
+ Pattern.CASE_INSENSITIVE);
+
+ /**
+ * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
+ * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
+ *
+ * @param method
+ * @return short string representation
+ */
+ public static String asString(Method method)
+ {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append(method.getDeclaringClass().getName());
+ buffer.append(".");
+ buffer.append(method.getName());
+ buffer.append("(");
+
+ for (int i = 0; i < method.getParameterTypes().length; i++)
+ {
+ if (i > 0)
+ buffer.append(", ");
+
+ String name = method.getParameterTypes()[i].getSimpleName();
+
+ buffer.append(name);
+ }
+
+ return buffer.append(")").toString();
+ }
+
+ /**
+ * Strips leading "_" and "$" and trailing "_" from the name.
+ */
+ public static String stripMemberName(String memberName)
+ {
+ assert InternalCommonsUtils.isNonBlank(memberName);
+ Matcher matcher = NAME_PATTERN.matcher(memberName);
+
+ if (!matcher.matches())
+ throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
+
+ return matcher.group(1);
+ }
+
+ /**
+ * Joins together some number of elements to form a comma separated list.
+ */
+ public static String join(List elements)
+ {
+ return InternalCommonsUtils.join(elements, ", ");
+ }
+
+ /**
+ * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
+ * string "(blank)".
+ *
+ * @param elements
+ * objects to be joined together
+ * @param separator
+ * used between elements when joining
+ */
+ public static String join(List elements, String separator)
+ {
+ switch (elements.size())
+ {
+ case 0:
+ return "";
+
+ case 1:
+ return elements.get(0).toString();
+
+ default:
+
+ StringBuilder buffer = new StringBuilder();
+ boolean first = true;
+
+ for (Object o : elements)
+ {
+ if (!first)
+ buffer.append(separator);
+
+ String string = String.valueOf(o);
+
+ if (string.equals(""))
+ string = "(blank)";
+
+ buffer.append(string);
+
+ first = false;
+ }
+
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
+ *
+ * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
+ * empty
+ */
+ public static String joinSorted(Collection elements)
+ {
+ if (elements == null || elements.isEmpty())
+ return "(none)";
+
+ List<String> list = CollectionFactory.newList();
+
+ for (Object o : elements)
+ list.add(String.valueOf(o));
+
+ Collections.sort(list);
+
+ return join(list);
+ }
+
+ /**
+ * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
+ */
+
+ public static boolean isBlank(String input)
+ {
+ return input == null || input.length() == 0 || input.trim().length() == 0;
+ }
+
+ /**
+ * Capitalizes a string, converting the first character to uppercase.
+ */
+ public static String capitalize(String input)
+ {
+ if (input.length() == 0)
+ return input;
+
+ return input.substring(0, 1).toUpperCase() + input.substring(1);
+ }
+
+ public static boolean isNonBlank(String input)
+ {
+ return !isBlank(input);
+ }
+
+ /**
+ * Return true if the input string contains the marker for symbols that must be expanded.
+ */
+ public static boolean containsSymbols(String input)
+ {
+ return input.contains("${");
+ }
+
+ /**
+ * Searches the string for the final period ('.') character and returns everything after that. The input string is
+ * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
+ * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
+ * character.
+ */
+ public static String lastTerm(String input)
+ {
+ assert isNonBlank(input);
+ int dotx = input.lastIndexOf('.');
+
+ if (dotx < 0)
+ return input;
+
+ return input.substring(dotx + 1);
+ }
+
+ /**
+ * Extracts the string keys from a map and returns them in sorted order. The keys are converted to strings.
+ *
+ * @param map
+ * the map to extract keys from (may be null)
+ * @return the sorted keys, or the empty set if map is null
+ */
+
+ public static List<String> sortedKeys(Map map)
+ {
+ if (map == null)
+ return Collections.emptyList();
+
+ List<String> keys = CollectionFactory.newList();
+
+ for (Object o : map.keySet())
+ keys.add(String.valueOf(o));
+
+ Collections.sort(keys);
+
+ return keys;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
deleted file mode 100644
index e345593..0000000
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalStringUtils.java
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2006-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.ioc.internal.util;
-
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * String-related utilities used within various internal implementations of the Apache Tapestry subprojects.
- * Broken off Tapestry-IoC's InternalUtils.
- */
-@SuppressWarnings("all")
-public class InternalStringUtils
-{
-
- /**
- * Pattern used to eliminate leading and trailing underscores and dollar signs.
- */
- private static final Pattern NAME_PATTERN = Pattern.compile("^[_|$]*([\\p{javaJavaIdentifierPart}]+?)[_|$]*$",
- Pattern.CASE_INSENSITIVE);
-
- /**
- * Converts a method to a user presentable string consisting of the containing class name, the method name, and the
- * short form of the parameter list (the class name of each parameter type, shorn of the package name portion).
- *
- * @param method
- * @return short string representation
- */
- public static String asString(Method method)
- {
- StringBuilder buffer = new StringBuilder();
-
- buffer.append(method.getDeclaringClass().getName());
- buffer.append(".");
- buffer.append(method.getName());
- buffer.append("(");
-
- for (int i = 0; i < method.getParameterTypes().length; i++)
- {
- if (i > 0)
- buffer.append(", ");
-
- String name = method.getParameterTypes()[i].getSimpleName();
-
- buffer.append(name);
- }
-
- return buffer.append(")").toString();
- }
-
- /**
- * Strips leading "_" and "$" and trailing "_" from the name.
- */
- public static String stripMemberName(String memberName)
- {
- assert isNonBlank(memberName);
- Matcher matcher = NAME_PATTERN.matcher(memberName);
-
- if (!matcher.matches())
- throw new IllegalArgumentException(String.format("Input '%s' is not a valid Java identifier.", memberName));
-
- return matcher.group(1);
- }
-
- /**
- * Joins together some number of elements to form a comma separated list.
- */
- public static String join(List elements)
- {
- return join(elements, ", ");
- }
-
- /**
- * Joins together some number of elements. If a value in the list is the empty string, it is replaced with the
- * string "(blank)".
- *
- * @param elements
- * objects to be joined together
- * @param separator
- * used between elements when joining
- */
- public static String join(List elements, String separator)
- {
- switch (elements.size())
- {
- case 0:
- return "";
-
- case 1:
- return elements.get(0).toString();
-
- default:
-
- StringBuilder buffer = new StringBuilder();
- boolean first = true;
-
- for (Object o : elements)
- {
- if (!first)
- buffer.append(separator);
-
- String string = String.valueOf(o);
-
- if (string.equals(""))
- string = "(blank)";
-
- buffer.append(string);
-
- first = false;
- }
-
- return buffer.toString();
- }
- }
-
- /**
- * Creates a sorted copy of the provided elements, then turns that into a comma separated list.
- *
- * @return the elements converted to strings, sorted, joined with comma ... or "(none)" if the elements are null or
- * empty
- */
- public static String joinSorted(Collection elements)
- {
- if (elements == null || elements.isEmpty())
- return "(none)";
-
- List<String> list = CollectionFactory.newList();
-
- for (Object o : elements)
- list.add(String.valueOf(o));
-
- Collections.sort(list);
-
- return join(list);
- }
-
- /**
- * Returns true if the input is null, or is a zero length string (excluding leading/trailing whitespace).
- */
-
- public static boolean isBlank(String input)
- {
- return input == null || input.length() == 0 || input.trim().length() == 0;
- }
-
- public static boolean isNonBlank(String input)
- {
- return !isBlank(input);
- }
-
- /**
- * Capitalizes a string, converting the first character to uppercase.
- */
- public static String capitalize(String input)
- {
- if (input.length() == 0)
- return input;
-
- return input.substring(0, 1).toUpperCase() + input.substring(1);
- }
-
- /**
- * Return true if the input string contains the marker for symbols that must be expanded.
- */
- public static boolean containsSymbols(String input)
- {
- return input.contains("${");
- }
-
- /**
- * Searches the string for the final period ('.') character and returns everything after that. The input string is
- * generally a fully qualified class name, though tapestry-core also uses this method for the occasional property
- * expression (which is also dot separated). Returns the input string unchanged if it does not contain a period
- * character.
- */
- public static String lastTerm(String input)
- {
- assert isNonBlank(input);
- int dotx = input.lastIndexOf('.');
-
- if (dotx < 0)
- return input;
-
- return input.substring(dotx + 1);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
new file mode 100644
index 0000000..41de363
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/LockSupport.java
@@ -0,0 +1,89 @@
+// Copyright 2012 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.ioc.internal.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base class for classes that need to manage a ReadWriteLock.
+ */
+public abstract class LockSupport
+{
+ private final Lock readLock, writeLock;
+
+ protected LockSupport()
+ {
+ ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+ readLock = lock.readLock();
+ writeLock = lock.writeLock();
+ }
+
+ /**
+ * Locks the shared read lock. Any number of threads may lock the read lock at the same time.
+ */
+ protected final void acquireReadLock()
+ {
+ readLock.lock();
+ }
+
+ /**
+ * Takes the exclusive write lock. Once started, no other thread lock the read or write lock. When this method returns,
+ * this thread will have locked the write lock and no other thread will have either the read or write lock.
+ * Note that this thread must first drop the read lock (if it has it) before attempting to take the write lock, or this method will block forever.
+ */
+ protected final void takeWriteLock()
+ {
+ writeLock.lock();
+ }
+
+ /**
+ * Releases the shared read lock.
+ */
+ protected final void releaseReadLock()
+ {
+ readLock.unlock();
+ }
+
+ /**
+ * Releases the exclusive read lock.
+ */
+ protected final void releaseWriteLock()
+ {
+ writeLock.unlock();
+ }
+
+ /**
+ * Releases the read lock, then takes the write lock. There's a short window where the thread will have neither lock:
+ * during that window, some other thread may have a chance to take the write lock. In code, you'll often see a second check
+ * inside the code that has the write lock to see if the update to perform is still necessary.
+ */
+ protected final void upgradeReadLockToWriteLock()
+ {
+ releaseReadLock();
+ // This is that instant where another thread may grab the write lock. Very rare, but possible.
+ takeWriteLock();
+ }
+
+ /**
+ * Takes the read lock then releases the write lock.
+ */
+ protected final void downgradeWriteLockToReadLock()
+ {
+ acquireReadLock();
+ releaseWriteLock();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
new file mode 100644
index 0000000..f4d8949
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessageFormatterImpl.java
@@ -0,0 +1,65 @@
+// Copyright 2006-2013 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.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+
+import java.util.Locale;
+
+
+public class MessageFormatterImpl implements MessageFormatter
+{
+ private final String format;
+
+ private final Locale locale;
+
+ public MessageFormatterImpl(String format, Locale locale)
+ {
+ this.format = format;
+ this.locale = locale;
+ }
+
+ @Override
+ public String format(Object... args)
+ {
+ for (int i = 0; i < args.length; i++)
+ {
+ Object arg = args[i];
+
+ if (Throwable.class.isInstance(arg))
+ {
+ args[i] = ExceptionUtils.toMessage((Throwable) arg);
+ }
+ }
+
+ // Might be tempting to create a Formatter object and just keep reusing it ... but
+ // Formatters are not threadsafe.
+
+ return String.format(locale, format, args);
+ }
+
+ /**
+ * Returns the underlying format string for this formatter.
+ *
+ * @since 5.4
+ */
+ @Override
+ public String toString()
+ {
+ return format;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
new file mode 100644
index 0000000..c06ef90
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/MessagesImpl.java
@@ -0,0 +1,74 @@
+// Copyright 2006, 2012 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.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.util.AbstractMessages;
+
+import java.util.*;
+
+/**
+ * Implementation of {@link org.apache.tapestry5.ioc.Messages} based around a {@link java.util.ResourceBundle}.
+ */
+public class MessagesImpl extends AbstractMessages
+{
+ private final Map<String, String> properties = CollectionFactory.newCaseInsensitiveMap();
+
+ /**
+ * Finds the messages for a given Messages utility class. Strings the trailing "Messages" and replaces it with
+ * "Strings" to form the base path. Loads the bundle using the default locale, and the class' class loader.
+ *
+ * @param forClass
+ * @return Messages for the class
+ */
+ public static Messages forClass(Class forClass)
+ {
+ String className = forClass.getName();
+ String stringsClassName = className.replaceAll("Messages$", "Strings");
+
+ Locale locale = Locale.getDefault();
+
+ ResourceBundle bundle = ResourceBundle.getBundle(stringsClassName, locale, forClass.getClassLoader());
+
+ return new MessagesImpl(locale, bundle);
+ }
+
+ public MessagesImpl(Locale locale, ResourceBundle bundle)
+ {
+ super(locale);
+
+ // Our best (threadsafe) chance to determine all the available keys.
+ Enumeration<String> e = bundle.getKeys();
+ while (e.hasMoreElements())
+ {
+ String key = e.nextElement();
+ String value = bundle.getString(key);
+
+ properties.put(key, value);
+ }
+ }
+
+ @Override
+ protected String valueForKey(String key)
+ {
+ return properties.get(key);
+ }
+
+ @Override
+ public Set<String> getKeys()
+ {
+ return properties.keySet();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
index d8d8018..6e23c5b 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -34,7 +34,7 @@ public class TapestryException extends RuntimeException implements Locatable
*/
public TapestryException(String message, Object location, Throwable cause)
{
- this(message, locationOf(location), cause);
+ this(message, InternalCommonsUtils.locationOf(location), cause);
}
/**
@@ -71,26 +71,5 @@ public class TapestryException extends RuntimeException implements Locatable
return String.format("%s [at %s]", super.toString(), location);
}
-
- /**
- * Sniffs the object to see if it is a {@link Location} or {@link Locatable}. Returns null if null or not
- * convertable to a location.
- * Copied from InternalUtils to avoid having it moved to BeanModel or Commons subprojects.
- */
-
- private static Location locationOf(Object location)
- {
- if (location == null)
- return null;
-
- if (location instanceof Location)
- return (Location) location;
-
- if (location instanceof Locatable)
- return ((Locatable) location).getLocation();
-
- return null;
- }
-
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
new file mode 100644
index 0000000..590c337
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AbstractMessages.java
@@ -0,0 +1,94 @@
+// Copyright 2006, 2009, 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.ioc.util;
+
+import org.apache.tapestry5.ioc.MessageFormatter;
+import org.apache.tapestry5.ioc.Messages;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.MessageFormatterImpl;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Abstract implementation of {@link Messages} that doesn't know where values come from (that information is supplied in
+ * a subclass, via the {@link #valueForKey(String)} method).
+ */
+public abstract class AbstractMessages implements Messages
+{
+ /**
+ * String key to MF instance.
+ */
+ private final Map<String, MessageFormatter> cache = CollectionFactory.newConcurrentMap();
+
+ private final Locale locale;
+
+ protected AbstractMessages(Locale locale)
+ {
+ this.locale = locale;
+ }
+
+ /**
+ * Invoked to provide the value for a particular key. This may be invoked multiple times even for the same key. The
+ * implementation should <em>ignore the case of the key</em>.
+ *
+ * @param key the key to obtain a value for (case insensitive)
+ * @return the value for the key, or null if this instance can not provide the value
+ */
+ protected abstract String valueForKey(String key);
+
+
+ @Override
+ public boolean contains(String key)
+ {
+ return valueForKey(key) != null;
+ }
+
+ @Override
+ public String get(String key)
+ {
+ if (contains(key)) return valueForKey(key);
+
+ return String.format("[[missing key: %s]]", key);
+ }
+
+ @Override
+ public MessageFormatter getFormatter(String key)
+ {
+ MessageFormatter result = cache.get(key);
+
+ if (result == null)
+ {
+ result = buildMessageFormatter(key);
+ cache.put(key, result);
+ }
+
+ return result;
+ }
+
+ private MessageFormatter buildMessageFormatter(String key)
+ {
+ String format = get(key);
+
+ return new MessageFormatterImpl(format, locale);
+ }
+
+ @Override
+ public String format(String key, Object... args)
+ {
+ return getFormatter(key).format(args);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
index 8c9cb3f..b2f1386 100644
--- a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -20,7 +20,7 @@ import java.util.List;
import java.util.Map;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalStringUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
/**
* Used (as part of a {@link UnknownValueException} to identify what available values
@@ -81,7 +81,7 @@ public class AvailableValues
@Override
public String toString()
{
- return String.format("AvailableValues[%s: %s]", valueType, InternalStringUtils.join(values));
+ return String.format("AvailableValues[%s: %s]", valueType, InternalCommonsUtils.join(values));
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
new file mode 100644
index 0000000..01ef99e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/TimeInterval.java
@@ -0,0 +1,195 @@
+// 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.ioc.util;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+
+/**
+ * Used to represent a period of time, specifically as a configuration value. This is often used to specify timeouts.
+ * <p/>
+ * TimePeriods are parsed from strings.
+ * <p/>
+ * The string specifys a number of terms. The values of all the terms are summed together to form the total time period.
+ * Each term consists of a number followed by a unit. Units (from largest to smallest) are: <dl> <dt>y <dd>year <dt>d
+ * <dd>day <dt>h <dd>hour <dt>m <dd>minute <dt>s <dd>second <dt>ms <dd>millisecond </dl> <p> Example: "2 h 30 m". By
+ * convention, terms are specified largest to smallest. A term without a unit is assumed to be milliseconds. Units are
+ * case insensitive ("h" or "H" are treated the same).
+ */
+public class TimeInterval
+{
+ private static final Map<String, Long> UNITS = CollectionFactory.newCaseInsensitiveMap();
+
+ private static final long MILLISECOND = 1000l;
+
+ static
+ {
+ UNITS.put("ms", 1l);
+ UNITS.put("s", MILLISECOND);
+ UNITS.put("m", 60 * MILLISECOND);
+ UNITS.put("h", 60 * UNITS.get("m"));
+ UNITS.put("d", 24 * UNITS.get("h"));
+ UNITS.put("y", 365 * UNITS.get("d"));
+ }
+
+ /**
+ * The unit keys, sorted in descending order.
+ */
+ private static final String[] UNIT_KEYS =
+ { "y", "d", "h", "m", "s", "ms" };
+
+ private static final Pattern PATTERN = Pattern.compile("\\s*(\\d+)\\s*([a-z]*)", Pattern.CASE_INSENSITIVE);
+
+ private final long milliseconds;
+
+ /**
+ * Creates a TimeInterval for a string.
+ *
+ * @param input
+ * the string specifying the amount of time in the period
+ */
+ public TimeInterval(String input)
+ {
+ this(parseMilliseconds(input));
+ }
+
+ public TimeInterval(long milliseconds)
+ {
+ this.milliseconds = milliseconds;
+ }
+
+ public long milliseconds()
+ {
+ return milliseconds;
+ }
+
+ public long seconds()
+ {
+ return milliseconds / MILLISECOND;
+ }
+
+ /**
+ * Converts the milliseconds back into a string (compatible with {@link #TimeInterval(String)}).
+ *
+ * @since 5.2.0
+ */
+ public String toDescription()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ String sep = "";
+
+ long remainder = milliseconds;
+
+ for (String key : UNIT_KEYS)
+ {
+ if (remainder == 0)
+ break;
+
+ long value = UNITS.get(key);
+
+ long units = remainder / value;
+
+ if (units > 0)
+ {
+ builder.append(sep);
+ builder.append(units);
+ builder.append(key);
+
+ sep = " ";
+
+ remainder = remainder % value;
+ }
+ }
+
+ return builder.toString();
+ }
+
+ static long parseMilliseconds(String input)
+ {
+ long milliseconds = 0l;
+
+ Matcher matcher = PATTERN.matcher(input);
+
+ matcher.useAnchoringBounds(true);
+
+ // TODO: Notice non matching characters and reject input, including at end
+
+ int lastMatchEnd = -1;
+
+ while (matcher.find())
+ {
+ int start = matcher.start();
+
+ if (lastMatchEnd + 1 < start)
+ {
+ String invalid = input.substring(lastMatchEnd + 1, start);
+ throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+ }
+
+ lastMatchEnd = matcher.end();
+
+ long count = Long.parseLong(matcher.group(1));
+ String units = matcher.group(2);
+
+ if (units.length() == 0)
+ {
+ milliseconds += count;
+ continue;
+ }
+
+ Long unitValue = UNITS.get(units);
+
+ if (unitValue == null)
+ throw new RuntimeException(String.format("Unknown time interval unit '%s' (in '%s'). Defined units: %s.", units, input, InternalCommonsUtils.joinSorted(UNITS.keySet())));
+
+ milliseconds += count * unitValue;
+ }
+
+ if (lastMatchEnd + 1 < input.length())
+ {
+ String invalid = input.substring(lastMatchEnd + 1);
+ throw new RuntimeException(String.format("Unexpected string '%s' (in time interval '%s').", invalid, input));
+ }
+
+ return milliseconds;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("TimeInterval[%d ms]", milliseconds);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ if (obj instanceof TimeInterval)
+ {
+ TimeInterval tp = (TimeInterval) obj;
+
+ return milliseconds == tp.milliseconds;
+ }
+
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
new file mode 100644
index 0000000..bdde866
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/util/StringToEnumCoercion.java
@@ -0,0 +1,91 @@
+// 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.util;
+
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalCommonsUtils;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+
+/**
+ * A {@link org.apache.tapestry5.ioc.services.Coercion} for converting strings into an instance of a particular
+ * enumerated type. The {@link Enum#name() name} is used as the key to identify the enum instance, in a case-insensitive
+ * fashion.
+ * <p>
+ * Moved from tapestry-core to tapestry-ioc is release 5.3, but kept in same package for compatibility.
+ *
+ * @param <T>
+ * the type of enumeration
+ */
+public final class StringToEnumCoercion<T extends Enum> implements Coercion<String, T>
+{
+ private final Class<T> enumClass;
+
+ private final Map<String, T> stringToEnum = CollectionFactory.newCaseInsensitiveMap();
+
+ public StringToEnumCoercion(Class<T> enumClass)
+ {
+ this(enumClass, enumClass.getEnumConstants());
+ }
+
+ public StringToEnumCoercion(Class<T> enumClass, T... values)
+ {
+ this.enumClass = enumClass;
+
+ for (T value : values)
+ stringToEnum.put(value.name(), value);
+ }
+
+ @Override
+ public T coerce(String input)
+ {
+ if (InternalCommonsUtils.isBlank(input))
+ return null;
+
+ T result = stringToEnum.get(input);
+
+ if (result == null)
+ {
+ String message = String.format("Input '%s' does not identify a value from enumerated type %s.", input,
+ enumClass.getName());
+
+ throw new UnknownValueException(message, new AvailableValues(enumClass.getName() + " enum constants",
+ stringToEnum));
+ }
+
+ return result;
+ }
+
+ /**
+ * Allows an alias value (alternate) string to reference a value.
+ *
+ * @since 5.2.2
+ */
+ public StringToEnumCoercion<T> addAlias(String alias, T value)
+ {
+ stringToEnum.put(alias, value);
+
+ return this;
+ }
+
+ public static <T extends Enum> StringToEnumCoercion<T> create(Class<T> enumClass)
+ {
+ return new StringToEnumCoercion<T>(enumClass);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
index e69377f..e032975 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
@@ -59,7 +59,7 @@ public class TapestryInternalUtils
*/
public static String toUserPresentable(String id)
{
- return InternalBeanModelUtils.toUserPresentable(id);
+ return InternalUtils.toUserPresentable(id);
}
public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
@@ -228,7 +228,7 @@ public class TapestryInternalUtils
*/
public static String extractIdFromPropertyExpression(String expression)
{
- return InternalBeanModelUtils.extractIdFromPropertyExpression(expression);
+ return InternalUtils.extractIdFromPropertyExpression(expression);
}
/**
@@ -237,7 +237,7 @@ public class TapestryInternalUtils
*/
public static String defaultLabel(String id, Messages messages, String propertyExpression)
{
- return InternalBeanModelUtils.defaultLabel(id, messages, propertyExpression);
+ return InternalUtils.defaultLabel(id, messages, propertyExpression);
}
/**
@@ -304,7 +304,7 @@ public class TapestryInternalUtils
private static String replace(String input, Pattern pattern, String replacement)
{
- return InternalBeanModelUtils.replace(input, pattern, replacement);
+ return InternalUtils.replace(input, pattern, replacement);
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
deleted file mode 100644
index 43519dc..0000000
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StringInternerImpl.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2009, 2012 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 org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.services.ComponentClasses;
-import org.apache.tapestry5.services.InvalidationEventHub;
-
-import javax.annotation.PostConstruct;
-import java.util.Map;
-
-public class StringInternerImpl implements StringInterner
-{
- private final Map<String, String> cache = CollectionFactory.newConcurrentMap();
-
- @PostConstruct
- public void setupInvalidation(@ComponentClasses InvalidationEventHub hub)
- {
- hub.clearOnInvalidation(cache);
- }
-
- public String intern(String string)
- {
- String result = cache.get(string);
-
- // Not yet in the cache? Add it.
-
- if (result == null)
- {
- cache.put(string, string);
- result = string;
- }
-
- return result;
- }
-
- public String format(String format, Object... arguments)
- {
- return intern(String.format(format, arguments));
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
deleted file mode 100644
index 03814f5..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/Configuration.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2006, 2008, 2009 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.ioc;
-
-/**
- * Object passed into a service contributor method that allows the method provide contributed values to the service's
- * configuration.
- * <p/>
- * A service can <em>collect</em> contributions in three different ways:
- * <ul>
- * <li>As an un-ordered collection of values</li>
- * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
- * <li>As a map of keys and values
- * </ul>
- * <p/>
- * This implementation is used for un-ordered configuration data.
- * <p/>
- * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
- * must be compatible with the type.
- */
-public interface Configuration<T>
-{
- /**
- * Adds an object to the service's contribution.
- *
- * @param object
- * to add to the service's configuration
- */
- void add(T object);
-
- /**
- * Automatically instantiates an instance of the class, with dependencies injected, and adds it to the
- * configuration. When the configuration type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the class will be created and contributed.
- *
- * @param clazz
- * what class to instantiate
- * @since 5.1.0.0
- */
- void addInstance(Class<? extends T> clazz);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
deleted file mode 100644
index 47c6026..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/MappedConfiguration.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2006, 2008, 2009, 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.ioc;
-
-/**
- * Object passed into a service contributor method that allows the method provide contributed values to the service's
- * configuration.
- * <p/>
- * A service can <em>collect</em> contributions in three different ways:
- * <ul>
- * <li>As an un-ordered collection of values</li>
- * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
- * <li>As a map of keys and values
- * </ul>
- * <p/>
- * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
- * must be compatible with the type.
- */
-public interface MappedConfiguration<K, V>
-{
-
- /**
- * Adds a keyed object to the service's contribution.
- *
- * @param key
- * unique id for the value
- * @param value
- * to contribute
- * @throws IllegalArgumentException
- * if key is not unique
- */
- void add(K key, V value);
-
- /**
- * Overrides an existing contribution by its key.
- *
- * @param key
- * unique id of value to override
- * @param value
- * new value, or null to remove the key entirely
- * @since 5.1.0.0
- */
- void override(K key, V value);
-
- /**
- * Adds a keyed object as an instantiated instance (with dependencies injected) of a class. When the value
- * type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the value class will be created and contributed.
- *
- * @param key
- * unique id for the value
- * @param clazz
- * class to instantiate and contribute
- * @since 5.1.0.0
- */
- void addInstance(K key, Class<? extends V> clazz);
-
- /**
- * Overrides an existing contribution with a new instance. When the value
- * type is an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the value class will be created and contributed.
- *
- * @param key
- * unique id of value to override
- * @param clazz
- * class to instantiate as override
- */
- void overrideInstance(K key, Class<? extends V> clazz);
-}
[06/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
new file mode 100644
index 0000000..701420f
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
@@ -0,0 +1,1563 @@
+// Copyright 2007-2013 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 org.antlr.runtime.ANTLRInputStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.tree.Tree;
+import org.apache.tapestry5.PropertyConduit;
+import org.apache.tapestry5.PropertyConduit2;
+import org.apache.tapestry5.internal.InternalPropertyConduit;
+import org.apache.tapestry5.internal.antlr.PropertyExpressionLexer;
+import org.apache.tapestry5.internal.antlr.PropertyExpressionParser;
+import org.apache.tapestry5.internal.util.IntegerRange;
+import org.apache.tapestry5.internal.util.MultiKey;
+import org.apache.tapestry5.ioc.AnnotationProvider;
+import org.apache.tapestry5.ioc.annotations.PostInjection;
+import org.apache.tapestry5.ioc.internal.NullAnnotationProvider;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.ExceptionUtils;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+import org.apache.tapestry5.plastic.*;
+import org.apache.tapestry5.services.ComponentClasses;
+import org.apache.tapestry5.services.ComponentLayer;
+import org.apache.tapestry5.services.InvalidationEventHub;
+import org.apache.tapestry5.services.PropertyConduitSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.tapestry5.internal.antlr.PropertyExpressionParser.*;
+
+public class PropertyConduitSourceImpl implements PropertyConduitSource
+{
+ static class ConduitMethods
+ {
+ private static final MethodDescription GET = getMethodDescription(PropertyConduit.class, "get", Object.class);
+
+ private static final MethodDescription SET = getMethodDescription(PropertyConduit.class, "set", Object.class,
+ Object.class);
+
+ private static final MethodDescription GET_PROPERTY_TYPE = getMethodDescription(PropertyConduit.class,
+ "getPropertyType");
+
+ private static final MethodDescription GET_PROPERTY_GENERIC_TYPE = getMethodDescription(PropertyConduit2.class,
+ "getPropertyGenericType");
+
+ private static final MethodDescription GET_PROPERTY_NAME = getMethodDescription(InternalPropertyConduit.class,
+ "getPropertyName");
+
+ private static final MethodDescription GET_ANNOTATION = getMethodDescription(AnnotationProvider.class,
+ "getAnnotation", Class.class);
+
+ }
+
+ static class DelegateMethods
+ {
+ static final Method INVERT = getMethod(PropertyConduitDelegate.class, "invert", Object.class);
+
+ static final Method RANGE = getMethod(PropertyConduitDelegate.class, "range", int.class, int.class);
+
+ static final Method COERCE = getMethod(PropertyConduitDelegate.class, "coerce", Object.class, Class.class);
+ }
+
+ static class ArrayListMethods
+ {
+ static final Method ADD = getMethod(ArrayList.class, "add", Object.class);
+ }
+
+ static class HashMapMethods
+ {
+ static final Method PUT = getMethod(HashMap.class, "put", Object.class, Object.class);
+ }
+
+ private static InstructionBuilderCallback RETURN_NULL = new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadNull().returnResult();
+ }
+ };
+
+ private static final String[] SINGLE_OBJECT_ARGUMENT = new String[]
+ {Object.class.getName()};
+
+ @SuppressWarnings("unchecked")
+ private static Method getMethod(Class containingClass, String name, Class... parameterTypes)
+ {
+ try
+ {
+ return containingClass.getMethod(name, parameterTypes);
+ } catch (NoSuchMethodException ex)
+ {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+
+ private static MethodDescription getMethodDescription(Class containingClass, String name, Class... parameterTypes)
+ {
+ return new MethodDescription(getMethod(containingClass, name, parameterTypes));
+ }
+
+ private final AnnotationProvider nullAnnotationProvider = new NullAnnotationProvider();
+
+ /**
+ * How are null values in intermdiate terms to be handled?
+ */
+ private enum NullHandling
+ {
+ /**
+ * Add code to check for null and throw exception if null.
+ */
+ FORBID,
+
+ /**
+ * Add code to check for null and short-circuit (i.e., the "?."
+ * safe-dereference operator)
+ */
+ ALLOW
+ }
+
+ /**
+ * One term in an expression. Expressions start with some root type and each term advances
+ * to a new type.
+ */
+ private class Term
+ {
+ /**
+ * The generic type of the term.
+ */
+ final Type type;
+
+ final Class genericType;
+
+ /**
+ * Describes the term, for use in error messages.
+ */
+ final String description;
+
+ final AnnotationProvider annotationProvider;
+
+ /**
+ * Callback that will implement the term.
+ */
+ final InstructionBuilderCallback callback;
+
+ Term(Type type, Class genericType, String description, AnnotationProvider annotationProvider,
+ InstructionBuilderCallback callback)
+ {
+ this.type = type;
+ this.genericType = genericType;
+ this.description = description;
+ this.annotationProvider = annotationProvider;
+ this.callback = callback;
+ }
+
+ Term(Type type, String description, AnnotationProvider annotationProvider, InstructionBuilderCallback callback)
+ {
+ this(type, GenericsUtils.asClass(type), description, annotationProvider, callback);
+ }
+
+ Term(Type type, String description, InstructionBuilderCallback callback)
+ {
+ this(type, description, null, callback);
+ }
+
+ /**
+ * Returns a clone of this Term with a new callback.
+ */
+ Term withCallback(InstructionBuilderCallback newCallback)
+ {
+ return new Term(type, genericType, description, annotationProvider, newCallback);
+ }
+ }
+
+ private final PropertyAccess access;
+
+ private final PlasticProxyFactory proxyFactory;
+
+ private final TypeCoercer typeCoercer;
+
+ private final StringInterner interner;
+
+ /**
+ * Keyed on combination of root class and expression.
+ */
+ private final Map<MultiKey, PropertyConduit> cache = CollectionFactory.newConcurrentMap();
+
+ private final Invariant invariantAnnotation = new Invariant()
+ {
+ public Class<? extends Annotation> annotationType()
+ {
+ return Invariant.class;
+ }
+ };
+
+ private final AnnotationProvider invariantAnnotationProvider = new AnnotationProvider()
+ {
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ if (annotationClass == Invariant.class)
+ return annotationClass.cast(invariantAnnotation);
+
+ return null;
+ }
+ };
+
+ private final PropertyConduit literalTrue;
+
+ private final PropertyConduit literalFalse;
+
+ private final PropertyConduit literalNull;
+
+ private final PropertyConduitDelegate sharedDelegate;
+
+ /**
+ * Encapsulates the process of building a PropertyConduit instance from an
+ * expression, as an {@link PlasticClassTransformer}.
+ */
+ class PropertyConduitBuilder implements PlasticClassTransformer
+ {
+ private final Class rootType;
+
+ private final String expression;
+
+ private final Tree tree;
+
+ private Class conduitPropertyType;
+
+ private Type conduitPropertyGenericType;
+
+ private String conduitPropertyName;
+
+ private AnnotationProvider annotationProvider = nullAnnotationProvider;
+
+ private PlasticField delegateField;
+
+ private PlasticClass plasticClass;
+
+ private PlasticMethod getRootMethod, navMethod;
+
+ PropertyConduitBuilder(Class rootType, String expression, Tree tree)
+ {
+ this.rootType = rootType;
+ this.expression = expression;
+ this.tree = tree;
+ }
+
+ public void transform(PlasticClass plasticClass)
+ {
+ this.plasticClass = plasticClass;
+
+ // Create the various methods; also determine the conduit's property type, property name and identify
+ // the annotation provider.
+
+ implementNavMethodAndAccessors();
+
+ implementOtherMethods();
+
+ plasticClass.addToString(String.format("PropertyConduit[%s %s]", rootType.getName(), expression));
+ }
+
+ private void implementOtherMethods()
+ {
+ PlasticField annotationProviderField = plasticClass.introduceField(AnnotationProvider.class,
+ "annotationProvider").inject(annotationProvider);
+
+ plasticClass.introduceMethod(ConduitMethods.GET_ANNOTATION).delegateTo(annotationProviderField);
+
+ plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_NAME, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadConstant(conduitPropertyName).returnResult();
+ }
+ });
+
+ final PlasticField propertyTypeField = plasticClass.introduceField(Class.class, "propertyType").inject(
+ conduitPropertyType);
+
+ plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_TYPE, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadThis().getField(propertyTypeField).returnResult();
+ }
+ });
+
+ final PlasticField propertyGenericTypeField = plasticClass.introduceField(Type.class, "propertyGenericType").inject(
+ conduitPropertyGenericType);
+
+ plasticClass.introduceMethod(ConduitMethods.GET_PROPERTY_GENERIC_TYPE, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadThis().getField(propertyGenericTypeField).returnResult();
+ }
+ });
+ }
+
+ /**
+ * Creates a method that does a conversion from Object to the expected root type, with
+ * a null check.
+ */
+ private void implementGetRoot()
+ {
+ getRootMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(rootType), "getRoot",
+ SINGLE_OBJECT_ARGUMENT, null);
+
+ getRootMethod.changeImplementation(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadArgument(0).dupe().when(Condition.NULL, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.throwException(NullPointerException.class,
+ String.format("Root object of property expression '%s' is null.", expression));
+ }
+ });
+
+ builder.checkcast(rootType).returnResult();
+ }
+ });
+ }
+
+ private boolean isLeaf(Tree node)
+ {
+ int type = node.getType();
+
+ return type != DEREF && type != SAFEDEREF;
+ }
+
+ private void implementNavMethodAndAccessors()
+ {
+ implementGetRoot();
+
+ // First, create the navigate method.
+
+ final List<InstructionBuilderCallback> callbacks = CollectionFactory.newList();
+
+ Type activeType = rootType;
+
+ Tree node = tree;
+
+ while (!isLeaf(node))
+ {
+ Term term = analyzeDerefNode(activeType, node);
+
+ callbacks.add(term.callback);
+
+ activeType = term.type;
+
+ // Second term is the continuation, possibly another chained
+ // DEREF, etc.
+ node = node.getChild(1);
+ }
+
+ Class activeClass = GenericsUtils.asClass(activeType);
+
+ if (callbacks.isEmpty())
+ {
+ navMethod = getRootMethod;
+ } else
+ {
+ navMethod = plasticClass.introducePrivateMethod(PlasticUtils.toTypeName(activeClass), "navigate",
+ SINGLE_OBJECT_ARGUMENT, null);
+
+ navMethod.changeImplementation(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+
+ for (InstructionBuilderCallback callback : callbacks)
+ {
+ callback.doBuild(builder);
+ }
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ implementAccessors(activeType, node);
+ }
+
+ private void implementAccessors(Type activeType, Tree node)
+ {
+ switch (node.getType())
+ {
+ case IDENTIFIER:
+
+ implementPropertyAccessors(activeType, node);
+
+ return;
+
+ case INVOKE:
+
+ // So, at this point, we have the navigation method written
+ // and it covers all but the terminal
+ // de-reference. node is an IDENTIFIER or INVOKE. We're
+ // ready to use the navigation
+ // method to implement get() and set().
+
+ implementMethodAccessors(activeType, node);
+
+ return;
+
+ case RANGEOP:
+
+ // As currently implemented, RANGEOP can only appear as the
+ // top level, which
+ // means we didn't need the navigate method after all.
+
+ implementRangeOpGetter(node);
+ implementNoOpSetter();
+
+ conduitPropertyType = IntegerRange.class;
+ conduitPropertyGenericType = IntegerRange.class;
+
+ return;
+
+ case LIST:
+
+ implementListGetter(node);
+ implementNoOpSetter();
+
+ conduitPropertyType = List.class;
+ conduitPropertyGenericType = List.class;
+
+ return;
+
+ case MAP:
+ implementMapGetter(node);
+ implementNoOpSetter();
+
+ conduitPropertyType = Map.class;
+ conduitPropertyGenericType = Map.class;
+
+ return;
+
+
+ case NOT:
+ implementNotOpGetter(node);
+ implementNoOpSetter();
+
+ conduitPropertyType = boolean.class;
+ conduitPropertyGenericType = boolean.class;
+
+ return;
+
+ default:
+ throw unexpectedNodeType(node, IDENTIFIER, INVOKE, RANGEOP, LIST, NOT);
+ }
+ }
+
+ public void implementMethodAccessors(final Type activeType, final Tree invokeNode)
+ {
+ final Term term = buildInvokeTerm(activeType, invokeNode);
+
+ implementNoOpSetter();
+
+ conduitPropertyName = term.description;
+ conduitPropertyType = term.genericType;
+ conduitPropertyGenericType = term.genericType;
+ annotationProvider = term.annotationProvider;
+
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ term.callback.doBuild(builder);
+
+ boxIfPrimitive(builder, conduitPropertyType);
+
+ builder.returnResult();
+ }
+ });
+
+ implementNoOpSetter();
+ }
+
+ public void implementPropertyAccessors(Type activeType, Tree identifierNode)
+ {
+ String propertyName = identifierNode.getText();
+
+ PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
+
+ conduitPropertyName = propertyName;
+ conduitPropertyType = adapter.getType();
+ conduitPropertyGenericType = getGenericType(adapter);
+ annotationProvider = adapter;
+
+ implementGetter(adapter);
+ implementSetter(adapter);
+ }
+
+ private Type getGenericType(PropertyAdapter adapter)
+ {
+ Type genericType = null;
+ if (adapter.getField() != null)
+ {
+ genericType = adapter.getField().getGenericType();
+ }
+ else if (adapter.getReadMethod() != null)
+ {
+ genericType = adapter.getReadMethod().getGenericReturnType();
+ }
+ else if (adapter.getWriteMethod() != null)
+ {
+ genericType = adapter.getWriteMethod().getGenericParameterTypes()[0];
+ }
+ else
+ {
+ throw new RuntimeException("Could not find accessor for property " + adapter.getName());
+ }
+
+ return genericType == null ? adapter.getType() : genericType;
+ }
+
+ private void implementSetter(PropertyAdapter adapter)
+ {
+ if (adapter.getWriteMethod() != null)
+ {
+ implementSetter(adapter.getWriteMethod());
+ return;
+ }
+
+ if (adapter.getField() != null && adapter.isUpdate())
+ {
+ implementSetter(adapter.getField());
+ return;
+ }
+
+ implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
+ rootType.getName());
+ }
+
+ private boolean isStatic(Member member)
+ {
+ return Modifier.isStatic(member.getModifiers());
+ }
+
+ private void implementSetter(final Field field)
+ {
+ if (isStatic(field))
+ {
+ plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+ builder.putStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ builder.returnResult();
+ }
+ });
+
+ return;
+ }
+
+ plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ builder.loadArgument(1).castOrUnbox(PlasticUtils.toTypeName(field.getType()));
+
+ builder.putField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private void implementSetter(final Method writeMethod)
+ {
+ plasticClass.introduceMethod(ConduitMethods.SET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ Class propertyType = writeMethod.getParameterTypes()[0];
+ String propertyTypeName = PlasticUtils.toTypeName(propertyType);
+
+ builder.loadArgument(1).castOrUnbox(propertyTypeName);
+
+ builder.invoke(writeMethod);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private void implementGetter(PropertyAdapter adapter)
+ {
+ if (adapter.getReadMethod() != null)
+ {
+ implementGetter(adapter.getReadMethod());
+ return;
+ }
+
+ if (adapter.getField() != null)
+ {
+ implementGetter(adapter.getField());
+ return;
+ }
+
+ implementNoOpMethod(ConduitMethods.GET, "Expression '%s' for class %s is write-only.", expression,
+ rootType.getName());
+ }
+
+ private void implementGetter(final Field field)
+ {
+ if (isStatic(field))
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.getStaticField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ // Cast not necessary here since the return type of get() is Object
+
+ boxIfPrimitive(builder, field.getType());
+
+ builder.returnResult();
+ }
+ });
+
+ return;
+ }
+
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ builder.getField(field.getDeclaringClass().getName(), field.getName(), field.getType());
+
+ // Cast not necessary here since the return type of get() is Object
+
+ boxIfPrimitive(builder, field.getType());
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private void implementGetter(final Method readMethod)
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeNavigateMethod(builder);
+
+ invokeMethod(builder, readMethod, null, 0);
+
+ boxIfPrimitive(builder, conduitPropertyType);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private void implementRangeOpGetter(final Tree rangeNode)
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ // Put the delegate on top of the stack
+
+ builder.loadThis().getField(getDelegateField());
+
+ invokeMethod(builder, DelegateMethods.RANGE, rangeNode, 0);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ /**
+ * @param node
+ * subexpression to invert
+ */
+ private void implementNotOpGetter(final Tree node)
+ {
+ // Implement get() as navigate, then do a method invocation based on node
+ // then, then pass (wrapped) result to delegate.invert()
+
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ Type expressionType = implementNotExpression(builder, node);
+
+ // Yes, we know this will always be the case, for now.
+
+ boxIfPrimitive(builder, expressionType);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ /**
+ * The first part of any implementation of get() or set(): invoke the navigation method
+ * and if the result is null, return immediately.
+ */
+ private void invokeNavigateMethod(InstructionBuilder builder)
+ {
+ builder.loadThis().loadArgument(0).invokeVirtual(navMethod);
+
+ builder.dupe().when(Condition.NULL, RETURN_NULL);
+ }
+
+ /**
+ * Uses the builder to add instructions for a subexpression.
+ *
+ * @param builder
+ * used to add instructions
+ * @param activeType
+ * type of value on top of the stack when this code will execute, or null if no value on stack
+ * @param node
+ * defines the expression
+ * @return the expression type
+ */
+ private Type implementSubexpression(InstructionBuilder builder, Type activeType, Tree node)
+ {
+ Term term;
+
+ while (true)
+ {
+ switch (node.getType())
+ {
+ case IDENTIFIER:
+ case INVOKE:
+
+ if (activeType == null)
+ {
+ invokeGetRootMethod(builder);
+
+ activeType = rootType;
+ }
+
+ term = buildTerm(activeType, node);
+
+ term.callback.doBuild(builder);
+
+ return term.type;
+
+ case INTEGER:
+
+ builder.loadConstant(new Long(node.getText()));
+
+ return long.class;
+
+ case DECIMAL:
+
+ builder.loadConstant(new Double(node.getText()));
+
+ return double.class;
+
+ case STRING:
+
+ builder.loadConstant(node.getText());
+
+ return String.class;
+
+ case DEREF:
+ case SAFEDEREF:
+
+ if (activeType == null)
+ {
+ invokeGetRootMethod(builder);
+
+ activeType = rootType;
+ }
+
+ term = analyzeDerefNode(activeType, node);
+
+ term.callback.doBuild(builder);
+
+ activeType = GenericsUtils.asClass(term.type);
+
+ node = node.getChild(1);
+
+ break;
+
+ case TRUE:
+ case FALSE:
+
+ builder.loadConstant(node.getType() == TRUE ? 1 : 0);
+
+ return boolean.class;
+
+ case LIST:
+
+ return implementListConstructor(builder, node);
+
+ case MAP:
+ return implementMapConstructor(builder, node);
+
+ case NOT:
+
+ return implementNotExpression(builder, node);
+
+ case THIS:
+
+ invokeGetRootMethod(builder);
+
+ return rootType;
+
+ case NULL:
+
+ builder.loadNull();
+
+ return Void.class;
+
+ default:
+ throw unexpectedNodeType(node, TRUE, FALSE, INTEGER, DECIMAL, STRING, DEREF, SAFEDEREF,
+ IDENTIFIER, INVOKE, LIST, NOT, THIS, NULL);
+ }
+ }
+ }
+
+ public void invokeGetRootMethod(InstructionBuilder builder)
+ {
+ builder.loadThis().loadArgument(0).invokeVirtual(getRootMethod);
+ }
+
+ private void implementListGetter(final Tree listNode)
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ implementListConstructor(builder, listNode);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private Type implementListConstructor(InstructionBuilder builder, Tree listNode)
+ {
+ // First, create an empty instance of ArrayList
+
+ int count = listNode.getChildCount();
+
+ builder.newInstance(ArrayList.class);
+ builder.dupe().loadConstant(count).invokeConstructor(ArrayList.class, int.class);
+
+ for (int i = 0; i < count; i++)
+ {
+ builder.dupe(); // the ArrayList
+
+ Type expressionType = implementSubexpression(builder, null, listNode.getChild(i));
+
+ boxIfPrimitive(builder, GenericsUtils.asClass(expressionType));
+
+ // Add the value to the array, then pop off the returned boolean
+ builder.invoke(ArrayListMethods.ADD).pop();
+ }
+
+ return ArrayList.class;
+ }
+
+ private void implementMapGetter(final Tree mapNode)
+ {
+ plasticClass.introduceMethod(ConduitMethods.GET, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ implementMapConstructor(builder, mapNode);
+
+ builder.returnResult();
+ }
+ });
+ }
+
+ private Type implementMapConstructor(InstructionBuilder builder, Tree mapNode)
+ {
+ int count = mapNode.getChildCount();
+ builder.newInstance(HashMap.class);
+ builder.dupe().loadConstant(count).invokeConstructor(HashMap.class, int.class);
+
+ for (int i = 0; i < count; i += 2)
+ {
+ builder.dupe();
+
+ //build the key:
+ Type keyType = implementSubexpression(builder, null, mapNode.getChild(i));
+ boxIfPrimitive(builder, GenericsUtils.asClass(keyType));
+
+ //and the value:
+ Type valueType = implementSubexpression(builder, null, mapNode.getChild(i + 1));
+ boxIfPrimitive(builder, GenericsUtils.asClass(valueType));
+
+ //put the value into the array, then pop off the returned object.
+ builder.invoke(HashMapMethods.PUT).pop();
+
+ }
+
+ return HashMap.class;
+ }
+
+
+ private void implementNoOpSetter()
+ {
+ implementNoOpMethod(ConduitMethods.SET, "Expression '%s' for class %s is read-only.", expression,
+ rootType.getName());
+ }
+
+ public void implementNoOpMethod(MethodDescription method, String format, Object... arguments)
+ {
+ final String message = String.format(format, arguments);
+
+ plasticClass.introduceMethod(method).changeImplementation(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ builder.throwException(RuntimeException.class, message);
+ }
+ });
+ }
+
+ /**
+ * Invokes a method that may take parameters. The children of the invokeNode are subexpressions
+ * to be evaluated, and potentially coerced, so that they may be passed to the method.
+ *
+ * @param builder
+ * constructs code
+ * @param method
+ * method to invoke
+ * @param node
+ * INVOKE or RANGEOP node
+ * @param childOffset
+ * offset within the node to the first child expression (1 in an INVOKE node because the
+ * first child is the method name, 0 in a RANGEOP node)
+ */
+ private void invokeMethod(InstructionBuilder builder, Method method, Tree node, int childOffset)
+ {
+ // We start with the target object for the method on top of the stack.
+ // Next, we have to push each method parameter, which may include boxing/deboxing
+ // and coercion. Once the code is in good shape, there's a lot of room to optimize
+ // the bytecode (a bit too much boxing/deboxing occurs, as well as some unnecessary
+ // trips through TypeCoercer). We might also want to have a local variable to store
+ // the root object (result of getRoot()).
+
+ Class[] parameterTypes = method.getParameterTypes();
+
+ for (int i = 0; i < parameterTypes.length; i++)
+ {
+ Type expressionType = implementSubexpression(builder, null, node.getChild(i + childOffset));
+
+ // The value left on the stack is not primitive, and expressionType represents
+ // its real type.
+
+ Class parameterType = parameterTypes[i];
+
+ if (!parameterType.isAssignableFrom(GenericsUtils.asClass(expressionType)))
+ {
+ boxIfPrimitive(builder, expressionType);
+
+ builder.loadThis().getField(getDelegateField());
+ builder.swap().loadTypeConstant(PlasticUtils.toWrapperType(parameterType));
+ builder.invoke(DelegateMethods.COERCE);
+
+ if (parameterType.isPrimitive())
+ {
+ builder.castOrUnbox(parameterType.getName());
+ } else
+ {
+ builder.checkcast(parameterType);
+ }
+ }
+
+ // And that should leave an object of the correct type on the stack,
+ // ready for the method invocation.
+ }
+
+ // Now the target object and all parameters are in place.
+
+ builder.invoke(method.getDeclaringClass(), method.getReturnType(), method.getName(),
+ method.getParameterTypes());
+ }
+
+ /**
+ * Analyzes a DEREF or SAFEDEREF node, proving back a term that identifies its type and provides a callback to
+ * peform the dereference.
+ *
+ * @return a term indicating the type of the expression to this point, and a {@link InstructionBuilderCallback}
+ * to advance the evaluation of the expression form the previous value to the current
+ */
+ private Term analyzeDerefNode(Type activeType, Tree node)
+ {
+ // The first child is the term.
+
+ Tree term = node.getChild(0);
+
+ boolean allowNull = node.getType() == SAFEDEREF;
+
+ return buildTerm(activeType, term, allowNull ? NullHandling.ALLOW : NullHandling.FORBID);
+ }
+
+ private Term buildTerm(Type activeType, Tree term, final NullHandling nullHandling)
+ {
+ assertNodeType(term, IDENTIFIER, INVOKE);
+
+ final Term simpleTerm = buildTerm(activeType, term);
+
+ if (simpleTerm.genericType.isPrimitive())
+ return simpleTerm;
+
+ return simpleTerm.withCallback(new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ simpleTerm.callback.doBuild(builder);
+
+ builder.dupe().when(Condition.NULL, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ switch (nullHandling)
+ {
+ // It is necessary to load a null onto the stack (even if there's already one
+ // there) because of the verifier. It sees the return when the stack contains an
+ // intermediate value (along the navigation chain) and thinks the method is
+ // returning a value of the wrong type.
+
+ case ALLOW:
+ builder.loadNull().returnResult();
+
+ case FORBID:
+
+ builder.loadConstant(simpleTerm.description);
+ builder.loadConstant(expression);
+ builder.loadArgument(0);
+
+ builder.invokeStatic(PropertyConduitSourceImpl.class, NullPointerException.class,
+ "nullTerm", String.class, String.class, Object.class);
+ builder.throwException();
+
+ break;
+
+ }
+ }
+ });
+ }
+ });
+ }
+
+ private void assertNodeType(Tree node, int... expected)
+ {
+ int type = node.getType();
+
+ for (int e : expected)
+ {
+ if (type == e)
+ return;
+ }
+
+ throw unexpectedNodeType(node, expected);
+ }
+
+ private RuntimeException unexpectedNodeType(Tree node, int... expected)
+ {
+ List<String> tokenNames = CollectionFactory.newList();
+
+ for (int i = 0; i < expected.length; i++)
+ tokenNames.add(PropertyExpressionParser.tokenNames[expected[i]]);
+
+ String message = String.format("Node %s was type %s, but was expected to be (one of) %s.",
+ node.toStringTree(), PropertyExpressionParser.tokenNames[node.getType()],
+ InternalUtils.joinSorted(tokenNames));
+
+ return new RuntimeException(message);
+ }
+
+ private Term buildTerm(Type activeType, Tree termNode)
+ {
+ switch (termNode.getType())
+ {
+ case INVOKE:
+
+ return buildInvokeTerm(activeType, termNode);
+
+ case IDENTIFIER:
+
+ return buildPropertyAccessTerm(activeType, termNode);
+
+ default:
+ throw unexpectedNodeType(termNode, INVOKE, IDENTIFIER);
+ }
+ }
+
+ private Term buildPropertyAccessTerm(Type activeType, Tree termNode)
+ {
+ String propertyName = termNode.getText();
+
+ PropertyAdapter adapter = findPropertyAdapter(activeType, propertyName);
+
+ // Prefer the accessor over the field
+
+ if (adapter.getReadMethod() != null)
+ {
+ return buildGetterMethodAccessTerm(activeType, propertyName,
+ adapter.getReadMethod());
+ }
+
+ if (adapter.getField() != null)
+ {
+ return buildPublicFieldAccessTerm(activeType, propertyName,
+ adapter.getField());
+ }
+
+ throw new RuntimeException(String.format(
+ "Property '%s' of class %s is not readable (it has no read accessor method).", adapter.getName(),
+ adapter.getBeanType().getName()));
+ }
+
+ public PropertyAdapter findPropertyAdapter(Type activeType, String propertyName)
+ {
+ Class activeClass = GenericsUtils.asClass(activeType);
+
+ ClassPropertyAdapter classAdapter = access.getAdapter(activeClass);
+ PropertyAdapter adapter = classAdapter.getPropertyAdapter(propertyName);
+
+ if (adapter == null)
+ {
+ final List<String> names = classAdapter.getPropertyNames();
+ final String className = activeClass.getName();
+ throw new UnknownValueException(String.format(
+ "Class %s does not contain a property (or public field) named '%s'.", className, propertyName),
+ new AvailableValues("Properties (and public fields)", names));
+ }
+ return adapter;
+ }
+
+ private Term buildGetterMethodAccessTerm(final Type activeType, String propertyName, final Method readMethod)
+ {
+ Type returnType = GenericsUtils.extractActualType(activeType, readMethod);
+
+ return new Term(returnType, propertyName, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeMethod(builder, readMethod, null, 0);
+
+ Type genericType = GenericsUtils.extractActualType(activeType, readMethod);
+
+ castToGenericType(builder, readMethod.getReturnType(), genericType);
+ }
+ });
+ }
+
+ private Term buildPublicFieldAccessTerm(Type activeType, String propertyName, final Field field)
+ {
+ final Type fieldType = GenericsUtils.extractActualType(activeType, field);
+
+ return new Term(fieldType, propertyName, new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ Class rawFieldType = field.getType();
+
+ String rawTypeName = PlasticUtils.toTypeName(rawFieldType);
+ String containingClassName = field.getDeclaringClass().getName();
+ String fieldName = field.getName();
+
+ if (isStatic(field))
+ {
+ // We've gone to the trouble of loading the root object, or navigated to some other object,
+ // but we don't need or want the instance, since it's a static field we're accessing.
+ // Ideally, we would optimize this, and only generate and invoke the getRoot() and nav() methods as needed, but
+ // access to public fields is relatively rare, and the cost is just the unused bytecode.
+
+ builder.pop();
+
+ builder.getStaticField(containingClassName, fieldName, rawTypeName);
+
+ } else
+ {
+ builder.getField(containingClassName, fieldName, rawTypeName);
+ }
+
+ castToGenericType(builder, rawFieldType, fieldType);
+ }
+
+ });
+ }
+
+ /**
+ * Casts the results of a field read or method invocation based on generic information.
+ *
+ * @param builder
+ * used to add instructions
+ * @param rawType
+ * the simple type (often Object) of the field (or method return type)
+ * @param genericType
+ * the generic Type, from which parameterizations can be determined
+ */
+ private void castToGenericType(InstructionBuilder builder, Class rawType, final Type genericType)
+ {
+ if (!genericType.equals(rawType))
+ {
+ Class castType = GenericsUtils.asClass(genericType);
+ builder.checkcast(castType);
+ }
+ }
+
+ private Term buildInvokeTerm(final Type activeType, final Tree invokeNode)
+ {
+ String methodName = invokeNode.getChild(0).getText();
+
+ int parameterCount = invokeNode.getChildCount() - 1;
+
+ Class activeClass = GenericsUtils.asClass(activeType);
+
+ final Method method = findMethod(activeClass, methodName, parameterCount);
+
+ if (method.getReturnType().equals(void.class))
+ throw new RuntimeException(String.format("Method %s.%s() returns void.", activeClass.getName(),
+ methodName));
+
+ Type returnType = GenericsUtils.extractActualType(activeType, method);
+
+ return new Term(returnType, toUniqueId(method), InternalUtils.toAnnotationProvider(method), new InstructionBuilderCallback()
+ {
+ public void doBuild(InstructionBuilder builder)
+ {
+ invokeMethod(builder, method, invokeNode, 1);
+
+ Type genericType = GenericsUtils.extractActualType(activeType, method);
+
+ castToGenericType(builder, method.getReturnType(), genericType);
+ }
+ }
+ );
+ }
+
+ private Method findMethod(Class activeType, String methodName, int parameterCount)
+ {
+ Class searchType = activeType;
+
+ while (true)
+ {
+
+ for (Method method : searchType.getMethods())
+ {
+ if (method.getParameterTypes().length == parameterCount
+ && method.getName().equalsIgnoreCase(methodName))
+ return method;
+ }
+
+ // TAP5-330
+ if (searchType != Object.class)
+ {
+ searchType = Object.class;
+ } else
+ {
+ throw new RuntimeException(String.format("Class %s does not contain a public method named '%s()'.",
+ activeType.getName(), methodName));
+ }
+ }
+ }
+
+ public void boxIfPrimitive(InstructionBuilder builder, Type termType)
+ {
+ boxIfPrimitive(builder, GenericsUtils.asClass(termType));
+ }
+
+ public void boxIfPrimitive(InstructionBuilder builder, Class termType)
+ {
+ if (termType.isPrimitive())
+ builder.boxPrimitive(termType.getName());
+ }
+
+ public Class implementNotExpression(InstructionBuilder builder, final Tree notNode)
+ {
+ Type expressionType = implementSubexpression(builder, null, notNode.getChild(0));
+
+ boxIfPrimitive(builder, expressionType);
+
+ // Now invoke the delegate invert() method
+
+ builder.loadThis().getField(getDelegateField());
+
+ builder.swap().invoke(DelegateMethods.INVERT);
+
+ return boolean.class;
+ }
+
+ /**
+ * Defer creation of the delegate field unless actually needed.
+ */
+ private PlasticField getDelegateField()
+ {
+ if (delegateField == null)
+ delegateField = plasticClass.introduceField(PropertyConduitDelegate.class, "delegate").inject(
+ sharedDelegate);
+
+ return delegateField;
+ }
+ }
+
+ public PropertyConduitSourceImpl(PropertyAccess access, @ComponentLayer
+ PlasticProxyFactory proxyFactory, TypeCoercer typeCoercer, StringInterner interner)
+ {
+ this.access = access;
+ this.proxyFactory = proxyFactory;
+ this.typeCoercer = typeCoercer;
+ this.interner = interner;
+
+ literalTrue = createLiteralConduit(Boolean.class, true);
+ literalFalse = createLiteralConduit(Boolean.class, false);
+ literalNull = createLiteralConduit(Void.class, null);
+
+ sharedDelegate = new PropertyConduitDelegate(typeCoercer);
+ }
+
+ @PostInjection
+ public void listenForInvalidations(@ComponentClasses InvalidationEventHub hub)
+ {
+ hub.clearOnInvalidation(cache);
+ }
+
+
+ public PropertyConduit create(Class rootClass, String expression)
+ {
+ assert rootClass != null;
+ assert InternalUtils.isNonBlank(expression);
+
+ MultiKey key = new MultiKey(rootClass, expression);
+
+ PropertyConduit result = cache.get(key);
+
+ if (result == null)
+ {
+ result = build(rootClass, expression);
+ cache.put(key, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Builds a subclass of {@link PropertyConduitDelegate} that implements the
+ * get() and set() methods and overrides the
+ * constructor. In a worst-case race condition, we may build two (or more)
+ * conduits for the same
+ * rootClass/expression, and it will get sorted out when the conduit is
+ * stored into the cache.
+ *
+ * @param rootClass
+ * class of root object for expression evaluation
+ * @param expression
+ * expression to be evaluated
+ * @return the conduit
+ */
+ private PropertyConduit build(final Class rootClass, String expression)
+ {
+ Tree tree = parse(expression);
+
+ try
+ {
+ switch (tree.getType())
+ {
+ case TRUE:
+
+ return literalTrue;
+
+ case FALSE:
+
+ return literalFalse;
+
+ case NULL:
+
+ return literalNull;
+
+ case INTEGER:
+
+ // Leading '+' may screw this up.
+ // TODO: Singleton instance for "0", maybe "1"?
+
+ return createLiteralConduit(Long.class, new Long(tree.getText()));
+
+ case DECIMAL:
+
+ // Leading '+' may screw this up.
+ // TODO: Singleton instance for "0.0"?
+
+ return createLiteralConduit(Double.class, new Double(tree.getText()));
+
+ case STRING:
+
+ return createLiteralConduit(String.class, tree.getText());
+
+ case RANGEOP:
+
+ Tree fromNode = tree.getChild(0);
+ Tree toNode = tree.getChild(1);
+
+ // If the range is defined as integers (not properties, etc.)
+ // then it is possible to calculate the value here, once, and not
+ // build a new class.
+
+ if (fromNode.getType() != INTEGER || toNode.getType() != INTEGER)
+ break;
+
+ int from = Integer.parseInt(fromNode.getText());
+ int to = Integer.parseInt(toNode.getText());
+
+ IntegerRange ir = new IntegerRange(from, to);
+
+ return createLiteralConduit(IntegerRange.class, ir);
+
+ case THIS:
+
+ return createLiteralThisPropertyConduit(rootClass);
+
+ default:
+ break;
+ }
+
+ return proxyFactory.createProxy(InternalPropertyConduit.class,
+ new PropertyConduitBuilder(rootClass, expression, tree)).newInstance();
+ } catch (Exception ex)
+ {
+ throw new PropertyExpressionException(String.format("Exception generating conduit for expression '%s': %s",
+ expression, ExceptionUtils.toMessage(ex)), expression, ex);
+ }
+ }
+
+ private PropertyConduit createLiteralThisPropertyConduit(final Class rootClass)
+ {
+ return new PropertyConduit()
+ {
+ public Object get(Object instance)
+ {
+ return instance;
+ }
+
+ public void set(Object instance, Object value)
+ {
+ throw new RuntimeException("Literal values are not updateable.");
+ }
+
+ public Class getPropertyType()
+ {
+ return rootClass;
+ }
+
+ public Type getPropertyGenericType()
+ {
+ return rootClass;
+ }
+
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return invariantAnnotationProvider.getAnnotation(annotationClass);
+ }
+ };
+ }
+
+ private <T> PropertyConduit createLiteralConduit(Class<T> type, T value)
+ {
+ return new LiteralPropertyConduit(typeCoercer, type, invariantAnnotationProvider, interner.format(
+ "LiteralPropertyConduit[%s]", value), value);
+ }
+
+ private Tree parse(String expression)
+ {
+ InputStream is = new ByteArrayInputStream(expression.getBytes());
+
+ ANTLRInputStream ais;
+
+ try
+ {
+ ais = new ANTLRInputStream(is);
+ } catch (IOException ex)
+ {
+ throw new RuntimeException(ex);
+ }
+
+ PropertyExpressionLexer lexer = new PropertyExpressionLexer(ais);
+
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+ PropertyExpressionParser parser = new PropertyExpressionParser(tokens);
+
+ try
+ {
+ return (Tree) parser.start().getTree();
+ } catch (Exception ex)
+ {
+ throw new RuntimeException(String.format("Error parsing property expression '%s': %s.", expression,
+ ex.getMessage()), ex);
+ }
+ }
+
+ /**
+ * May be invoked from fabricated PropertyConduit instances.
+ */
+ @SuppressWarnings("unused")
+ public static NullPointerException nullTerm(String term, String expression, Object root)
+ {
+ String message = String.format("Property '%s' (within property expression '%s', of %s) is null.", term,
+ expression, root);
+
+ return new NullPointerException(message);
+ }
+
+ private static String toUniqueId(Method method)
+ {
+ StringBuilder builder = new StringBuilder(method.getName()).append("(");
+ String sep = "";
+
+ for (Class parameterType : method.getParameterTypes())
+ {
+ builder.append(sep);
+ builder.append(PlasticUtils.toTypeName(parameterType));
+
+ sep = ",";
+ }
+
+ return builder.append(")").toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java b/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
new file mode 100644
index 0000000..16b4fca
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/services/BeanModelSource.java
@@ -0,0 +1,70 @@
+// 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.services;
+
+import org.apache.tapestry5.beaneditor.BeanModel;
+import org.apache.tapestry5.ioc.Messages;
+
+/**
+ * Used by a component to create a default {@link org.apache.tapestry5.beaneditor.BeanModel} for a particular bean
+ * class. Also provides support to the model by generating validation information for individual fields.
+ * <p/>
+ * BeanModels are the basis for the {@link org.apache.tapestry5.corelib.components.BeanEditor} and {@link
+ * org.apache.tapestry5.corelib.components.Grid} comopnents.
+ *
+ * @see org.apache.tapestry5.services.PropertyConduitSource
+ */
+public interface BeanModelSource
+{
+ /**
+ * Creates a new model used for editing the indicated bean class. The model will represent all read/write properties
+ * of the bean. The order of properties is determined from the order of the getter methods in the code, and can be
+ * overridden with the {@link org.apache.tapestry5.beaneditor.ReorderProperties} annotation. The labels for the
+ * properties are derived from the property names, but if the component's message catalog has keys of the form
+ * <code>propertyName-label</code>, then those will be used instead.
+ * <p/>
+ * Models are <em>mutable</em>, so they are not cached, a fresh instance is created each time.
+ *
+ * @param beanClass class of object to be edited
+ * @param filterReadOnlyProperties if true, then properties that are read-only will be skipped (leaving only
+ * read-write properties, appropriate for {@link org.apache.tapestry5.corelib.components.BeanEditForm},
+ * etc.). If false, then both read-only and read-write properties will be included
+ * (appropriate for {@link org.apache.tapestry5.corelib.components.Grid} or {@link
+ * org.apache.tapestry5.corelib.components.BeanDisplay}).
+ * @param messages Used to find explicit overrides of
+ * @return a model
+ * @deprecated use {@link #createDisplayModel(Class, org.apache.tapestry5.ioc.Messages)} or {@link
+ * #createEditModel(Class, org.apache.tapestry5.ioc.Messages)}
+ */
+ <T> BeanModel<T> create(Class<T> beanClass, boolean filterReadOnlyProperties, Messages messages);
+
+ /**
+ * Creates a model for display purposes; this may include properties which are read-only.
+ *
+ * @param beanClass class of object to be edited
+ * @param messages
+ * @return a model containing properties that can be presented to the user
+ */
+ <T> BeanModel<T> createDisplayModel(Class<T> beanClass, Messages messages);
+
+ /**
+ * Creates a model for edit and update purposes, only properties that are fully read-write are included.
+ *
+ * @param beanClass class of object to be edited
+ * @param messages
+ * @return a model containing properties that can be presented to the user
+ */
+ <T> BeanModel<T> createEditModel(Class<T> beanClass, Messages messages);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
----------------------------------------------------------------------
diff --git a/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java b/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
new file mode 100644
index 0000000..312cd60
--- /dev/null
+++ b/beanmodel/src/main/java/org/apache/tapestry5/services/PropertyConduitSource.java
@@ -0,0 +1,41 @@
+// Copyright 2007, 2008, 2009 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.services;
+
+import org.apache.tapestry5.PropertyConduit;
+
+/**
+ * A source for {@link org.apache.tapestry5.PropertyConduit}s, which can be thought of as a compiled property path
+ * expression. PropertyConduits are the basis of the "prop:" binding factory, thus this service defines the expression
+ * format used by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}.
+ */
+public interface PropertyConduitSource
+{
+ /**
+ * Returns a property conduit instance for the given expression. PropertyConduitSource caches the conduits it
+ * returns, so despite the name, this method does not always create a <em>new</em> conduit. The cache is cleared if
+ * a change to component classes is observed.
+ * <p/>
+ * Callers of this method should observe notifications from the {@link org.apache.tapestry5.services.InvalidationEventHub}
+ * for {@link org.apache.tapestry5.services.ComponentClasses} and discard any aquired conduits; failure to do so
+ * will create memory leaks whenever component classes change (the conduits will keep references to the old classes
+ * and classloaders).
+ *
+ * @param rootType the type of the root object to which the expression is applied
+ * @param expression expression to be evaluated on instances of the root class
+ * @return RuntimeException if the expression is invalid (poorly formed, references non-existent properties, etc.)
+ */
+ PropertyConduit create(Class rootType, String expression);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/build.gradle
----------------------------------------------------------------------
diff --git a/commons/build.gradle b/commons/build.gradle
new file mode 100644
index 0000000..76850ef
--- /dev/null
+++ b/commons/build.gradle
@@ -0,0 +1,18 @@
+import org.gradle.plugins.ide.idea.model.*
+import t5build.*
+
+description = "Project including common classes for tapestry-core, tapestry-ioc and beanmodel."
+
+//apply plugin: JavaPlugin
+
+buildDir = 'target/gradle-build'
+
+dependencies {
+ compile project(":plastic")
+ compile project(":tapestry5-annotations")
+}
+
+jar {
+ manifest {
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java b/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
new file mode 100644
index 0000000..7b2b7ab
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/util/IntegerRange.java
@@ -0,0 +1,125 @@
+// Copyright 2006 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.util;
+
+import java.util.Iterator;
+
+/**
+ * Represents a sequence of integer values, either ascending or descending. The sequence is always inclusive (of the
+ * finish value).
+ */
+public final class IntegerRange implements Iterable<Integer>
+{
+ private final int start;
+
+ private final int finish;
+
+ private class RangeIterator implements Iterator<Integer>
+ {
+ private final int increment;
+
+ private int value = start;
+
+ private boolean hasNext = true;
+
+ RangeIterator()
+ {
+ increment = start < finish ? +1 : -1;
+ }
+
+ public boolean hasNext()
+ {
+ return hasNext;
+ }
+
+ public Integer next()
+ {
+ if (!hasNext) throw new IllegalStateException();
+
+ int result = value;
+
+ hasNext = value != finish;
+
+ value += increment;
+
+ return result;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ public IntegerRange(final int start, final int finish)
+ {
+ this.start = start;
+ this.finish = finish;
+ }
+
+ public int getFinish()
+ {
+ return finish;
+ }
+
+ public int getStart()
+ {
+ return start;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%d..%d", start, finish);
+ }
+
+ /**
+ * The main puprose of a range object is to produce an Iterator. Since IntegerRange is iterable, it is useful with
+ * the Tapestry Loop component, but also with the Java for loop!
+ */
+ public Iterator<Integer> iterator()
+ {
+ return new RangeIterator();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int PRIME = 31;
+
+ int result = PRIME + finish;
+
+ result = PRIME * result + start;
+
+ return result;
+ }
+
+ /**
+ * Returns true if the other object is an IntegerRange with the same start and finish values.
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ final IntegerRange other = (IntegerRange) obj;
+ if (finish != other.finish) return false;
+
+ return start == other.start;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java b/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
new file mode 100644
index 0000000..503bb1f
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/internal/util/MultiKey.java
@@ -0,0 +1,86 @@
+// Copyright 2006 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.util;
+
+import java.util.Arrays;
+
+/**
+ * Combines multiple values to form a single composite key. MultiKey can often be used as an alternative to nested
+ * maps.
+ */
+public final class MultiKey
+{
+ private static final int PRIME = 31;
+
+ private final Object[] values;
+
+ private final int hashCode;
+
+ /**
+ * Creates a new instance from the provided values. It is assumed that the values provided are good map keys
+ * themselves -- immutable, with proper implementations of equals() and hashCode().
+ *
+ * @param values
+ */
+ public MultiKey(Object... values)
+ {
+ this.values = values;
+
+ hashCode = PRIME * Arrays.hashCode(this.values);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final MultiKey other = (MultiKey) obj;
+
+ return Arrays.equals(values, other.values);
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder("MultiKey[");
+
+ boolean first = true;
+
+ for (Object o : values)
+ {
+ if (!first)
+ builder.append(", ");
+
+ builder.append(o);
+
+ first = false;
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
new file mode 100644
index 0000000..1f0e744
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/AnnotationProvider.java
@@ -0,0 +1,33 @@
+// Copyright 2007, 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.ioc;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A source of annotations. This interface is used to mask where the annotations come from (for example, from a Method,
+ * a Class, or some other source).
+ */
+public interface AnnotationProvider
+{
+ /**
+ * Searches for the specified annotation, returning the matching annotation instance.
+ *
+ * @param <T>
+ * @param annotationClass used to select the annotation to return
+ * @return the annotation, or null if not found
+ */
+ <T extends Annotation> T getAnnotation(Class<T> annotationClass);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java b/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
new file mode 100644
index 0000000..37b6551
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Locatable.java
@@ -0,0 +1,27 @@
+// Copyright 2006, 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.ioc;
+
+/**
+ * Interface implemented by objects which carry a location tag. Defines a readable property, location.
+ */
+@SuppressWarnings({"JavaDoc"})
+public interface Locatable
+{
+ /**
+ * Returns the location associated with this object for error reporting purposes.
+ */
+ Location getLocation();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Location.java b/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
new file mode 100644
index 0000000..e6688c2
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Location.java
@@ -0,0 +1,38 @@
+// Copyright 2006 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.ioc;
+
+/**
+ * A kind of tag applied to other objects to identify where they came from, in terms of a file (the resource), a line
+ * number, and a column number. This is part of "line precise exception reporting", whereby errors at runtime can be
+ * tracked backwards to the files from which they were parsed or otherwise constructed.
+ */
+public interface Location
+{
+ /**
+ * The resource from which the object tagged with a location was derived.
+ */
+ Resource getResource();
+
+ /**
+ * The line number within the resource, if known, or -1 otherwise.
+ */
+ int getLine();
+
+ /**
+ * The column number within the line if known, or -1 otherwise.
+ */
+ int getColumn();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java b/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
new file mode 100644
index 0000000..e90eb65
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/MessageFormatter.java
@@ -0,0 +1,32 @@
+// Copyright 2006 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.ioc;
+
+/**
+ * Obtained from a {@link org.apache.tapestry5.ioc.Messages}, used to format messages for a specific localized message
+ * key.
+ */
+public interface MessageFormatter
+{
+ /**
+ * Formats the message. The arguments are passed to {@link java.util.Formatter} as is with one exception: Object of
+ * type {@link Throwable} are converted to their {@link Throwable#getMessage()} (or, if that is null, to the name of
+ * the class).
+ *
+ * @param args
+ * @return formatted string
+ */
+ String format(Object... args);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java b/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
new file mode 100644
index 0000000..ba7452c
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Messages.java
@@ -0,0 +1,61 @@
+// Copyright 2006, 2007, 2012 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.ioc;
+
+import java.util.Set;
+
+/**
+ * Provides access to a messages catalog, a set of properties files that provide localized messages for a particular
+ * locale. The message catalog consists of keys and values and follows the semantics of a Java {@link
+ * java.util.ResourceBundle} with some changes.
+ */
+public interface Messages
+{
+ /**
+ * Returns true if the bundle contains the named key.
+ */
+ boolean contains(String key);
+
+ /**
+ * Returns the localized message for the given key. If catalog does not contain such a key, then a modified version
+ * of the key is returned (converted to upper case and enclosed in brackets).
+ *
+ * @param key
+ * @return localized message for key, or placeholder
+ */
+ String get(String key);
+
+ /**
+ * Returns a formatter for the message, which can be used to substitute arguments (as per {@link
+ * java.util.Formatter}).
+ *
+ * @param key
+ * @return formattable object
+ */
+ MessageFormatter getFormatter(String key);
+
+ /**
+ * Convenience for accessing a formatter and formatting a localized message with arguments.
+ */
+ String format(String key, Object... args);
+
+ /**
+ * Returns a set of all the keys for which this instance may provide a value.
+ *
+ * @return set of keys
+ * @since 5.4
+ */
+ Set<String> getKeys();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
new file mode 100644
index 0000000..81d1f77
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -0,0 +1,143 @@
+// Copyright 2006, 2007, 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.ioc;
+
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.services.MasterObjectProvider;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Defines an object which can provide access to services defined within a {@link org.apache.tapestry5.ioc.Registry}, or
+ * to objects or object instances available by other means. Services are accessed via service id, or
+ * (when appropriate)
+ * by just service interface. The Registry itself implements this interface, as does
+ * {@link org.apache.tapestry5.ioc.ServiceResources}.
+ */
+public interface ObjectLocator
+{
+ /**
+ * Obtains a service via its unique service id. Returns the service's proxy. The service proxy
+ * implements the same
+ * interface as the actual service, and is used to instantiate the actual service only as needed
+ * (this is
+ * transparent to the application).
+ *
+ * @param <T>
+ * @param serviceId unique Service id used to locate the service object (may contain <em>symbols</em>,
+ * which
+ * will be expanded), case is ignored
+ * @param serviceInterface the interface implemented by the service (or an interface extended by the service
+ * interface)
+ * @return the service instance
+ * @throws RuntimeException if the service is not defined, or if an error occurs instantiating it
+ */
+ <T> T getService(String serviceId, Class<T> serviceInterface);
+
+ /**
+ * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+ * interface (which * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
+ * (not the service <em>implementation</em>), which may result in a failure due to extra
+ * matches.
+ *
+ * @param serviceInterface the interface the service implements
+ * @return the service's proxy
+ * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+ * services directly implement, or extend from, the service interface
+ * @see org.apache.tapestry5.ioc.annotations.Marker
+ */
+ <T> T getService(Class<T> serviceInterface);
+
+ /**
+ * Locates a service given a service interface and (optionally) some marker annotation types. A single service must implement the service
+ * interface (which * can be hard to guarantee) and by marked by all the marker types. The search takes into account inheritance of the service interface
+ * (not the service <em>implementation</em>), which may result in a failure due to extra
+ * matches. The ability to specify marker annotation types was added in 5.3
+ *
+ * @param serviceInterface the interface the service implements
+ * @param markerTypes Markers used to select a specific service that implements the interface
+ * @return the service's proxy
+ * @throws RuntimeException if the service does not exist (this is considered programmer error), or multiple
+ * services directly implement, or extend from, the service interface
+ * @see org.apache.tapestry5.ioc.annotations.Marker
+ * @since 5.3
+ */
+ <T> T getService(Class<T> serviceInterface, Class<? extends Annotation>... markerTypes);
+
+ /**
+ * Obtains an object indirectly, using the {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} service.
+ *
+ * @param objectType the type of object to be returned
+ * @param annotationProvider provides access to annotations on the field or parameter for which a value is to
+ * be
+ * obtained, which may be utilized in selecting an appropriate object, use
+ * <strong>null</strong> when annotations are not available (in which case, selection
+ * will
+ * be based only on the object type)
+ * @param <T>
+ * @return the requested object
+ * @see ObjectProvider
+ */
+ <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider);
+
+ /**
+ * Autobuilds a class by finding the public constructor with the most parameters. Services and other resources or
+ * dependencies will be injected into the parameters of the constructor and into private fields marked with the
+ * {@link Inject} annotation. There are two cases: constructing a service implementation, and constructing
+ * an arbitrary object. In the former case, many <em>service resources</em> are also available for injection, not
+ * just dependencies or objects provided via
+ * {@link MasterObjectProvider#provide(Class, AnnotationProvider, ObjectLocator, boolean)}.
+ *
+ * @param <T>
+ * @param clazz the type of object to instantiate
+ * @return the instantiated instance
+ * @throws RuntimeException if the autobuild fails
+ * @see MasterObjectProvider
+ */
+ <T> T autobuild(Class<T> clazz);
+
+ /**
+ * Preferred version of {@link #autobuild(Class)} that tracks the operation using
+ * {@link OperationTracker#invoke(String, Invokable)}.
+ *
+ * @param <T>
+ * @param description description used with {@link OperationTracker}
+ * @param clazz the type of object to instantiate
+ * @return the instantiated instance
+ * @throws RuntimeException if the autobuild fails
+ * @see MasterObjectProvider
+ * @since 5.2.0
+ */
+ <T> T autobuild(String description, Class<T> clazz);
+
+ /**
+ * Creates a proxy. The proxy will defer invocation of {@link #autobuild(Class)} until
+ * just-in-time (that is, first method invocation). In a limited number of cases, it is necessary to use such a
+ * proxy to prevent service construction cycles, particularly when contributing (directly or indirectly) to the
+ * {@link org.apache.tapestry5.ioc.services.MasterObjectProvider} (which is itself at the heart
+ * of autobuilding).
+ * <p/>
+ * If the class file for the class is a file on the file system (not a file packaged in a JAR), then the proxy will
+ * <em>autoreload</em>: changing the class file will result in the new class being reloaded and re-instantiated
+ * (with dependencies).
+ *
+ * @param <T>
+ * @param interfaceClass the interface implemented by the proxy
+ * @param implementationClass a concrete class that implements the interface
+ * @return a proxy
+ * @see #autobuild(Class)
+ */
+ <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass);
+}
[05/15] tapestry-5 git commit: First pass creating the BeanModel and
Commons packages. Lots of stuff moved around,
but no actual code changes so far
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java b/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
new file mode 100644
index 0000000..b81c1c5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/Resource.java
@@ -0,0 +1,108 @@
+// 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.ioc;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Locale;
+
+/**
+ * Represents a resource on the server that may be used for server side processing, or may be exposed to the client
+ * side. Generally, this represents an abstraction on top of files on the class path and files stored in the web
+ * application context.
+ * <p/>
+ * Resources are often used as map keys; they should be immutable and should implement hashCode() and equals().
+ */
+public interface Resource
+{
+
+ /**
+ * Returns true if the resource exists; if a stream to the content of the file may be opened. A resource exists
+ * if {@link #toURL()} returns a non-null value. Starting in release 5.3.4, the result of this is cached.
+ * <p/>
+ * Starting in 5.4, some "virtual resources", may return true even though {@link #toURL()} returns null.
+ *
+ * @return true if the resource exists, false if it does not
+ */
+ boolean exists();
+
+
+ /**
+ * Returns true if the resource is virtual, meaning this is no underlying file. Many operations are unsupported
+ * on virtual resources, including {@link #toURL()}, {@link #forLocale(java.util.Locale)},
+ * {@link #withExtension(String)}, {@link #getFile()}, {@link #getFolder()}, {@link #getPath()}}; these
+ * operations will throw an {@link java.lang.UnsupportedOperationException}.
+ *
+ * @since 5.4
+ */
+ boolean isVirtual();
+
+ /**
+ * Opens a stream to the content of the resource, or returns null if the resource does not exist. The native
+ * input stream supplied by the resource is wrapped in a {@link java.io.BufferedInputStream}.
+ *
+ * @return an open, buffered stream to the content, if available
+ */
+ InputStream openStream() throws IOException;
+
+ /**
+ * Returns the URL for the resource, or null if it does not exist. This value is lazily computed; starting in 5.3.4, subclasses may cache
+ * the result. Starting in 5.4, some "virtual resources" may return null.
+ */
+ URL toURL();
+
+ /**
+ * Returns a localized version of the resource. May return null if no such resource exists. Starting in release
+ * 5.3.4, the result of this method is cached internally.
+ */
+ Resource forLocale(Locale locale);
+
+ /**
+ * Returns a Resource based on a relative path, relative to the folder containing the resource. Understands the "."
+ * (current folder) and ".." (parent folder) conventions, and treats multiple sequential slashes as a single slash.
+ * <p/>
+ * Virtual resources (resources fabricated at runtime) return themselves.
+ */
+ Resource forFile(String relativePath);
+
+ /**
+ * Returns a new Resource with the extension changed (or, if the resource does not have an extension, the extension
+ * is added). The new Resource may not exist (that is, {@link #toURL()} may return null.
+ *
+ * @param extension
+ * to apply to the resource, such as "html" or "properties"
+ * @return the new resource
+ */
+ Resource withExtension(String extension);
+
+ /**
+ * Returns the portion of the path up to the last forward slash; this is the directory or folder portion of the
+ * Resource.
+ */
+ String getFolder();
+
+ /**
+ * Returns the file portion of the Resource path, everything that follows the final forward slash.
+ * <p/>
+ * Starting in 5.4, certain kinds of "virtual resources" may return null here.
+ */
+ String getFile();
+
+ /**
+ * Return the path (the combination of folder and file).
+ * <p/>
+ * Starting in 5.4, certain "virtual resources", may return an arbitrary value here.
+ */
+ String getPath();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
new file mode 100644
index 0000000..716b7c6
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/NullAnnotationProvider.java
@@ -0,0 +1,35 @@
+// 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.ioc.internal;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A null implementation of {@link AnnotationProvider}, used when there is not appropriate source of annotations.
+ */
+public class NullAnnotationProvider implements AnnotationProvider
+{
+ /**
+ * Always returns null.
+ */
+ @Override
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
+ {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
new file mode 100644
index 0000000..6711b1a
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/CollectionFactory.java
@@ -0,0 +1,139 @@
+// Copyright 2006, 2007, 2012 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.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.util.CaseInsensitiveMap;
+import org.apache.tapestry5.ioc.util.Stack;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Static factory methods to ease the creation of new collection types (when using generics). Most of these method
+ * leverage the compiler's ability to match generic types by return value. Typical usage (with a static import):
+ * <p/>
+ * <pre>
+ * Map<Foo, Bar> map = newMap();
+ * </pre>
+ * <p/>
+ * <p/>
+ * This is a replacement for:
+ * <p/>
+ * <pre>
+ * Map<Foo, Bar> map = new HashMap<Foo, Bar>();
+ * </pre>
+ */
+public final class CollectionFactory
+{
+ /**
+ * Constructs and returns a generic {@link HashMap} instance.
+ */
+ public static <K, V> Map<K, V> newMap()
+ {
+ return new HashMap<K, V>();
+ }
+
+ /**
+ * Constructs and returns a generic {@link java.util.HashSet} instance.
+ */
+ public static <T> Set<T> newSet()
+ {
+ return new HashSet<T>();
+ }
+
+ /**
+ * Contructs a new {@link HashSet} and initializes it using the provided collection.
+ */
+ public static <T, V extends T> Set<T> newSet(Collection<V> values)
+ {
+ return new HashSet<T>(values);
+ }
+
+ public static <T, V extends T> Set<T> newSet(V... values)
+ {
+ // Was a call to newSet(), but Sun JDK can't handle that. Fucking generics.
+ return new HashSet<T>(Arrays.asList(values));
+ }
+
+ /**
+ * Constructs a new {@link java.util.HashMap} instance by copying an existing Map instance.
+ */
+ public static <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map)
+ {
+ return new HashMap<K, V>(map);
+ }
+
+ /**
+ * Constructs a new concurrent map, which is safe to access via multiple threads.
+ */
+ public static <K, V> ConcurrentMap<K, V> newConcurrentMap()
+ {
+ return new ConcurrentHashMap<K, V>();
+ }
+
+ /**
+ * Contructs and returns a new generic {@link java.util.ArrayList} instance.
+ */
+ public static <T> List<T> newList()
+ {
+ return new ArrayList<T>();
+ }
+
+ /**
+ * Creates a new, fully modifiable list from an initial set of elements.
+ */
+ public static <T, V extends T> List<T> newList(V... elements)
+ {
+ // Was call to newList(), but Sun JDK can't handle that.
+ return new ArrayList<T>(Arrays.asList(elements));
+ }
+
+ /**
+ * Useful for queues.
+ */
+ public static <T> LinkedList<T> newLinkedList()
+ {
+ return new LinkedList<T>();
+ }
+
+ /**
+ * Constructs and returns a new {@link java.util.ArrayList} as a copy of the provided collection.
+ */
+ public static <T, V extends T> List<T> newList(Collection<V> list)
+ {
+ return new ArrayList<T>(list);
+ }
+
+ /**
+ * Constructs and returns a new {@link java.util.concurrent.CopyOnWriteArrayList}.
+ */
+ public static <T> List<T> newThreadSafeList()
+ {
+ return new CopyOnWriteArrayList<T>();
+ }
+
+ public static <T> Stack<T> newStack()
+ {
+ return new Stack<T>();
+ }
+
+ public static <V> Map<String, V> newCaseInsensitiveMap()
+ {
+ return new CaseInsensitiveMap<V>();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
new file mode 100644
index 0000000..1a6dd80
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
@@ -0,0 +1,615 @@
+// Copyright 2008, 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.ioc.internal.util;
+
+import java.lang.reflect.*;
+import java.util.LinkedList;
+
+/**
+ * Static methods related to the use of JDK 1.5 generics.
+ */
+@SuppressWarnings("unchecked")
+public class GenericsUtils
+{
+ /**
+ * Analyzes the method in the context of containingClass and returns the Class that is represented by
+ * the method's generic return type. Any parameter information in the generic return type is lost. If you want
+ * to preserve the type parameters of the return type consider using
+ * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
+ *
+ * @param containingClass class which either contains or inherited the method
+ * @param method method from which to extract the return type
+ * @return the class represented by the methods generic return type, resolved based on the context .
+ * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
+ * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+ * @see #asClass(java.lang.reflect.Type)
+ */
+ public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
+ {
+ return asClass(resolve(method.getGenericReturnType(), containingClass));
+ }
+
+
+ /**
+ * Analyzes the field in the context of containingClass and returns the Class that is represented by
+ * the field's generic type. Any parameter information in the generic type is lost, if you want
+ * to preserve the type parameters of the return type consider using
+ * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
+ *
+ * @param containingClass class which either contains or inherited the field
+ * @param field field from which to extract the type
+ * @return the class represented by the field's generic type, resolved based on the containingClass.
+ * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
+ * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+ * @see #asClass(java.lang.reflect.Type)
+ */
+ public static Class extractGenericFieldType(Class containingClass, Field field)
+ {
+ return asClass(resolve(field.getGenericType(), containingClass));
+ }
+
+ /**
+ * Analyzes the method in the context of containingClass and returns the Class that is represented by
+ * the method's generic return type. Any parameter information in the generic return type is lost.
+ *
+ * @param containingType Type which is/represents the class that either contains or inherited the method
+ * @param method method from which to extract the generic return type
+ * @return the generic type represented by the methods generic return type, resolved based on the containingType.
+ * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+ */
+ public static Type extractActualType(Type containingType, Method method)
+ {
+ return resolve(method.getGenericReturnType(), containingType);
+ }
+
+ /**
+ * Analyzes the method in the context of containingClass and returns the Class that is represented by
+ * the method's generic return type. Any parameter information in the generic return type is lost.
+ *
+ * @param containingType Type which is/represents the class that either contains or inherited the field
+ * @param field field from which to extract the generic return type
+ * @return the generic type represented by the methods generic return type, resolved based on the containingType.
+ * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+ */
+ public static Type extractActualType(Type containingType, Field field)
+ {
+ return resolve(field.getGenericType(), containingType);
+ }
+
+ /**
+ * Resolves the type parameter based on the context of the containingType.
+ * <p/>
+ * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
+ * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
+ * instance (e.g. List<E>; List<Map<Long, String>>, E would be returned as a ParameterizedType with the raw
+ * type Map and type arguments Long and String.
+ * <p/>
+ *
+ * @param type
+ * the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
+ * @param containingType
+ * the type which his
+ * @return
+ * the type resolved to the best of our ability.
+ * @since 5.2.?
+ */
+ public static Type resolve(final Type type, final Type containingType)
+ {
+ // The type isn't generic. (String, Long, etc)
+ if (type instanceof Class)
+ return type;
+
+ // List<T>, List<String>, List<T extends Number>
+ if (type instanceof ParameterizedType)
+ return resolve((ParameterizedType) type, containingType);
+
+ // T[], List<String>[], List<T>[]
+ if (type instanceof GenericArrayType)
+ return resolve((GenericArrayType) type, containingType);
+
+ // List<? extends T>, List<? extends Object & Comparable & Serializable>
+ if (type instanceof WildcardType)
+ return resolve((WildcardType) type, containingType);
+
+ // T
+ if (type instanceof TypeVariable)
+ return resolve((TypeVariable) type, containingType);
+
+ // I'm leaning towards an exception here.
+ return type;
+ }
+
+
+ /**
+ * Determines if the suspected super type is assignable from the suspected sub type.
+ *
+ * @param suspectedSuperType
+ * e.g. GenericDAO<Pet, String>
+ * @param suspectedSubType
+ * e.g. PetDAO extends GenericDAO<Pet,String>
+ * @return
+ * true if (sourceType)targetClass is a valid cast
+ */
+ public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
+ {
+ final Class suspectedSuperClass = asClass(suspectedSuperType);
+ final Class suspectedSubClass = asClass(suspectedSubType);
+
+ // The raw types need to be compatible.
+ if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
+ {
+ return false;
+ }
+
+ // From this point we know that the raw types are assignable.
+ // We need to figure out what the generic parameters in the targetClass are
+ // as they pertain to the sourceType.
+
+ if (suspectedSuperType instanceof WildcardType)
+ {
+ // ? extends Number
+ // needs to match all the bounds (there will only be upper bounds or lower bounds
+ for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
+ {
+ if (!isAssignableFrom(t, suspectedSubType)) return false;
+ }
+ for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
+ {
+ if (!isAssignableFrom(suspectedSubType, t)) return false;
+ }
+ return true;
+ }
+
+ Type curType = suspectedSubType;
+ Class curClass;
+
+ while (curType != null && !curType.equals(Object.class))
+ {
+ curClass = asClass(curType);
+
+ if (curClass.equals(suspectedSuperClass))
+ {
+ final Type resolved = resolve(curType, suspectedSubType);
+
+ if (suspectedSuperType instanceof Class)
+ {
+ if ( resolved instanceof Class )
+ return suspectedSuperType.equals(resolved);
+
+ // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
+ // types default to Object so they must be a match.
+ // e.g. Pair p = new StringLongPair();
+ // Pair p = new Pair<? extends Number, String>
+
+ return true;
+ }
+
+ if (suspectedSuperType instanceof ParameterizedType)
+ {
+ if (resolved instanceof ParameterizedType)
+ {
+ final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
+ final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
+ if (type1Arguments.length != type2Arguments.length) return false;
+
+ for (int i = 0; i < type1Arguments.length; ++i)
+ {
+ if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
+ }
+ return true;
+ }
+ }
+ else if (suspectedSuperType instanceof GenericArrayType)
+ {
+ if (resolved instanceof GenericArrayType)
+ {
+ return isAssignableFrom(
+ ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
+ ((GenericArrayType) resolved).getGenericComponentType()
+ );
+ }
+ }
+
+ return false;
+ }
+
+ final Type[] types = curClass.getGenericInterfaces();
+ for (Type t : types)
+ {
+ final Type resolved = resolve(t, suspectedSubType);
+ if (isAssignableFrom(suspectedSuperType, resolved))
+ return true;
+ }
+
+ curType = curClass.getGenericSuperclass();
+ }
+ return false;
+ }
+
+ /**
+ * Get the class represented by the reflected type.
+ * This method is lossy; You cannot recover the type information from the class that is returned.
+ * <p/>
+ * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
+ * is lost.
+ * <p/>
+ * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
+ * then {@code Object} is returned.
+ *
+ * @param actualType
+ * a Class, ParameterizedType, GenericArrayType
+ * @return the un-parameterized class associated with the type.
+ */
+ public static Class asClass(Type actualType)
+ {
+ if (actualType instanceof Class) return (Class) actualType;
+
+ if (actualType instanceof ParameterizedType)
+ {
+ final Type rawType = ((ParameterizedType) actualType).getRawType();
+ // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
+ // some other Type. We'll assume it's a Class.
+ // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
+ return (Class) rawType;
+ }
+
+ if (actualType instanceof GenericArrayType)
+ {
+ final Type type = ((GenericArrayType) actualType).getGenericComponentType();
+ return Array.newInstance(asClass(type), 0).getClass();
+ }
+
+ if (actualType instanceof TypeVariable)
+ {
+ // Support for List<T extends Number>
+ // There is always at least one bound. If no bound is specified in the source then it will be Object.class
+ return asClass(((TypeVariable) actualType).getBounds()[0]);
+ }
+
+ if (actualType instanceof WildcardType)
+ {
+ final WildcardType wildcardType = (WildcardType) actualType;
+ final Type[] bounds = wildcardType.getLowerBounds();
+ if (bounds != null && bounds.length > 0)
+ {
+ return asClass(bounds[0]);
+ }
+ // If there is no lower bounds then the only thing that makes sense is Object.
+ return Object.class;
+ }
+
+ throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
+ }
+
+ /**
+ * Convert the type into a string. The string representation approximates the code that would be used to define the
+ * type.
+ *
+ * @param type - the type.
+ * @return a string representation of the type, similar to how it was declared.
+ */
+ public static String toString(Type type)
+ {
+ if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
+ if ( type instanceof WildcardType ) return toString((WildcardType)type);
+ if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
+ if ( type instanceof Class )
+ {
+ final Class theClass = (Class) type;
+ return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
+ }
+ return type.toString();
+ }
+
+ /**
+ * Method to resolve a TypeVariable to its most
+ * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
+ * <p/>
+ * <p/>
+ * How to resolve a TypeVariable:<br/>
+ * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
+ * given may or may not be reifiable; it may be another TypeVariable for instance.
+ * <p/>
+ * Consider <br/>
+ * <i>class Pair>A,B> { A getA(){...}; ...}</i><br/>
+ * <i>class StringLongPair extends Pair>String, Long> { }</i><br/>
+ * <p/>
+ * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
+ * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
+ * <p/>
+ * To get to the Type provided by StringLongPair you access the generics information by calling
+ * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
+ * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
+ * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
+ * <p/>
+ * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
+ * the class. When a class implements a generic interface it must provide types for the interface and any generic
+ * methods implemented from the interface will be re-defined by the class with its generic type variables.
+ *
+ * @param typeVariable - the type variable to resolve.
+ * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
+ * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
+ * declaration and the containingType.
+ */
+ private static Type resolve(TypeVariable typeVariable, Type containingType)
+ {
+ // The generic declaration is either a Class, Method or Constructor
+ final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
+
+ if (!(genericDeclaration instanceof Class))
+ {
+ // It's a method or constructor. The best we can do here is try to resolve the bounds
+ // e.g. <T extends E> T getT(T param){} where E is defined by the class.
+ final Type bounds0 = typeVariable.getBounds()[0];
+ return resolve(bounds0, containingType);
+ }
+
+ final Class typeVariableOwner = (Class) genericDeclaration;
+
+ // find the typeOwner in the containingType's hierarchy
+ final LinkedList<Type> stack = new LinkedList<Type>();
+
+ // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
+ // containingType and not the super class.
+ if (containingType instanceof ParameterizedType)
+ {
+ stack.add(containingType);
+ }
+
+ Class theClass = asClass(containingType);
+ Type genericSuperclass = theClass.getGenericSuperclass();
+ while (genericSuperclass != null && // true for interfaces with no superclass
+ !theClass.equals(Object.class) &&
+ !theClass.equals(typeVariableOwner))
+ {
+ stack.addFirst(genericSuperclass);
+ theClass = asClass(genericSuperclass);
+ genericSuperclass = theClass.getGenericSuperclass();
+ }
+
+ int i = getTypeVariableIndex(typeVariable);
+ Type resolved = typeVariable;
+ for (Type t : stack)
+ {
+ if (t instanceof ParameterizedType)
+ {
+ resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
+ if (resolved instanceof Class) return resolved;
+ if (resolved instanceof TypeVariable)
+ {
+ // Need to look at the next class in the hierarchy
+ i = getTypeVariableIndex((TypeVariable) resolved);
+ continue;
+ }
+ return resolve(resolved, containingType);
+ }
+ }
+
+ // the only way we get here is if resolved is still a TypeVariable, otherwise an
+ // exception is thrown or a value is returned.
+ return ((TypeVariable) resolved).getBounds()[0];
+ }
+
+ /**
+ * @param type - something like List<T>[] or List<? extends T>[] or T[]
+ * @param containingType - the shallowest type in the hierarchy where type is defined.
+ * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
+ */
+ private static GenericArrayType resolve(GenericArrayType type, Type containingType)
+ {
+ final Type componentType = type.getGenericComponentType();
+
+ if (!(componentType instanceof Class))
+ {
+ final Type resolved = resolve(componentType, containingType);
+ return create(resolved);
+ }
+
+ return type;
+ }
+
+ /**
+ * @param type - something like List<T>, List<T extends Number>
+ * @param containingType - the shallowest type in the hierarchy where type is defined.
+ * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
+ */
+ private static ParameterizedType resolve(ParameterizedType type, Type containingType)
+ {
+ // Use a copy because we're going to modify it.
+ final Type[] types = type.getActualTypeArguments().clone();
+
+ boolean modified = resolve(types, containingType);
+ return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
+ }
+
+ /**
+ * @param type - something like List<? super T>, List<<? extends T>, List<? extends T & Comparable<? super T>>
+ * @param containingType - the shallowest type in the hierarchy where type is defined.
+ * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
+ */
+ private static WildcardType resolve(WildcardType type, Type containingType)
+ {
+ // Use a copy because we're going to modify them.
+ final Type[] upper = type.getUpperBounds().clone();
+ final Type[] lower = type.getLowerBounds().clone();
+
+ boolean modified = resolve(upper, containingType);
+ modified = modified || resolve(lower, containingType);
+
+ return modified ? create(upper, lower) : type;
+ }
+
+ /**
+ * @param types - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
+ * @param containingType - the shallowest type in the hierarchy where type is defined.
+ * @return true if any of the types were resolved.
+ */
+ private static boolean resolve(Type[] types, Type containingType)
+ {
+ boolean modified = false;
+ for (int i = 0; i < types.length; ++i)
+ {
+ Type t = types[i];
+ if (!(t instanceof Class))
+ {
+ modified = true;
+ final Type resolved = resolve(t, containingType);
+ if (!resolved.equals(t))
+ {
+ types[i] = resolved;
+ modified = true;
+ }
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * @param rawType - the un-parameterized type.
+ * @param ownerType - the outer class or null if the class is not defined within another class.
+ * @param typeArguments - type arguments.
+ * @return a copy of the type with the typeArguments replaced.
+ */
+ static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
+ {
+ return new ParameterizedType()
+ {
+ @Override
+ public Type[] getActualTypeArguments()
+ {
+ return typeArguments;
+ }
+
+ @Override
+ public Type getRawType()
+ {
+ return rawType;
+ }
+
+ @Override
+ public Type getOwnerType()
+ {
+ return ownerType;
+ }
+
+ @Override
+ public String toString()
+ {
+ return GenericsUtils.toString(this);
+ }
+ };
+ }
+
+ static GenericArrayType create(final Type componentType)
+ {
+ return new GenericArrayType()
+ {
+ @Override
+ public Type getGenericComponentType()
+ {
+ return componentType;
+ }
+
+ @Override
+ public String toString()
+ {
+ return GenericsUtils.toString(this);
+ }
+ };
+ }
+
+ /**
+ * @param upperBounds - e.g. ? extends Number
+ * @param lowerBounds - e.g. ? super Long
+ * @return An new copy of the type with the upper and lower bounds replaced.
+ */
+ static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
+ {
+
+ return new WildcardType()
+ {
+ @Override
+ public Type[] getUpperBounds()
+ {
+ return upperBounds;
+ }
+
+ @Override
+ public Type[] getLowerBounds()
+ {
+ return lowerBounds;
+ }
+
+ @Override
+ public String toString()
+ {
+ return GenericsUtils.toString(this);
+ }
+ };
+ }
+
+ static String toString(ParameterizedType pt)
+ {
+ String s = toString(pt.getActualTypeArguments());
+ return String.format("%s<%s>", toString(pt.getRawType()), s);
+ }
+
+ static String toString(GenericArrayType gat)
+ {
+ return String.format("%s[]", toString(gat.getGenericComponentType()));
+ }
+
+ static String toString(WildcardType wt)
+ {
+ final boolean isSuper = wt.getLowerBounds().length > 0;
+ return String.format("? %s %s",
+ isSuper ? "super" : "extends",
+ isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
+ }
+
+ static String toString(Type[] types)
+ {
+ StringBuilder sb = new StringBuilder();
+ for ( Type t : types )
+ {
+ sb.append(toString(t)).append(", ");
+ }
+ return sb.substring(0, sb.length() - 2);// drop last ,
+ }
+
+ /**
+ * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
+ * the actual type.
+ *
+ * @param typeVariable - the type variable in question.
+ * @return the index of the type variable in its declaring class/method/constructor's type parameters.
+ */
+ private static int getTypeVariableIndex(final TypeVariable typeVariable)
+ {
+ // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
+ final String typeVarName = typeVariable.getName();
+ final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
+ for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
+ {
+ // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
+ if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
+ return typeArgumentIndex;
+ }
+
+ // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
+ throw new RuntimeException(
+ String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
new file mode 100644
index 0000000..ef217cb
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/TapestryException.java
@@ -0,0 +1,75 @@
+// Copyright 2006 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.ioc.internal.util;
+
+import org.apache.tapestry5.ioc.Locatable;
+import org.apache.tapestry5.ioc.Location;
+
+/**
+ * Exception class used as a replacement for {@link java.lang.RuntimeException} when the exception is related to a
+ * particular location.
+ */
+public class TapestryException extends RuntimeException implements Locatable
+{
+ private static final long serialVersionUID = 6396903640977182682L;
+
+ private transient final Location location;
+
+ /**
+ * @param message a message (may be null)
+ * @param location implements {@link Location} or {@link Locatable}
+ * @param cause if not null, the root cause of the exception
+ */
+ public TapestryException(String message, Object location, Throwable cause)
+ {
+ this(message, InternalUtils.locationOf(location), cause);
+ }
+
+ /**
+ * @param message a message (may be null)
+ * @param cause if not null, the root cause of the exception, also used to set the location
+ */
+ public TapestryException(String message, Throwable cause)
+ {
+ this(message, cause, cause);
+ }
+
+ /**
+ * @param message a message (may be null)
+ * @param location location to associated with the exception, or null if not known
+ * @param cause if not null, the root cause of the exception
+ */
+ public TapestryException(String message, Location location, Throwable cause)
+ {
+ super(message, cause);
+
+ this.location = location;
+ }
+
+ @Override
+ public Location getLocation()
+ {
+ return location;
+ }
+
+ @Override
+ public String toString()
+ {
+ if (location == null) return super.toString();
+
+ return String.format("%s [at %s]", super.toString(), location);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
new file mode 100644
index 0000000..6159ed3
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/ClassPropertyAdapter.java
@@ -0,0 +1,79 @@
+// Copyright 2006, 2007, 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.ioc.services;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+/**
+ * Organizes all {@link org.apache.tapestry5.ioc.services.PropertyAdapter}s for a particular class.
+ * <p/>
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p/>
+ * When accessing properties by name, the case of the name is ignored.
+ */
+public interface ClassPropertyAdapter
+{
+ /**
+ * Returns the names of all properties, sorted into alphabetic order. This includes true properties
+ * (as defined in the JavaBeans specification), but also public fields. Starting in Tapestry 5.3, even public static fields are included.
+ */
+ List<String> getPropertyNames();
+
+ /**
+ * Returns the type of bean this adapter provides properties for.
+ */
+ Class getBeanType();
+
+ /**
+ * Returns the property adapter with the given name, or null if no such adapter exists.
+ *
+ * @param name of the property (case is ignored)
+ */
+ PropertyAdapter getPropertyAdapter(String name);
+
+ /**
+ * Reads the value of a property.
+ *
+ * @param instance the object to read a value from
+ * @param propertyName the name of the property to read (case is ignored)
+ * @throws UnsupportedOperationException if the property is write only
+ * @throws IllegalArgumentException if property does not exist
+ */
+ Object get(Object instance, String propertyName);
+
+ /**
+ * Updates the value of a property.
+ *
+ * @param instance the object to update
+ * @param propertyName the name of the property to update (case is ignored)
+ * @throws UnsupportedOperationException if the property is read only
+ * @throws IllegalArgumentException if property does not exist
+ */
+ void set(Object instance, String propertyName, Object value);
+
+ /**
+ * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
+ *
+ * @param instance the object to read a value from
+ * @param propertyName the name of the property to read (case is ignored)
+ * @param annotationClass the type of annotation to return
+ *
+ * @throws IllegalArgumentException if property does not exist
+ *
+ * @since 5.4
+ */
+ Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
new file mode 100644
index 0000000..b7a4cc8
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/Coercion.java
@@ -0,0 +1,31 @@
+// Copyright 2006 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.ioc.services;
+
+/**
+ * Responsible for converting from one type to another. This is used primarily around component parameters.
+ *
+ * @param <S> the source type (input)
+ * @param <T> the target type (output)
+ */
+public interface Coercion<S, T>
+{
+ /**
+ * Converts an input value.
+ *
+ * @param input the input value
+ */
+ T coerce(S input);
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
new file mode 100644
index 0000000..746de1e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/CoercionTuple.java
@@ -0,0 +1,145 @@
+// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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.ioc.services;
+
+import org.apache.tapestry5.plastic.PlasticUtils;
+
+/**
+ * An immutable object that represents a mapping from one type to another. This is also the contribution type when
+ * building the {@link org.apache.tapestry5.ioc.services.TypeCoercer} service. Wraps a
+ * {@link org.apache.tapestry5.ioc.services.Coercion} object that performs the work with additional properties that
+ * describe
+ * the input and output types of the coercion, needed when searching for an appropriate coercion (or sequence of
+ * coercions).
+ *
+ * @param <S>
+ * source (input) type
+ * @param <T>
+ * target (output) type
+ */
+public final class CoercionTuple<S, T>
+{
+ private final Class<S> sourceType;
+
+ private final Class<T> targetType;
+
+ private final Coercion<S, T> coercion;
+
+ /**
+ * Wraps an arbitrary coercion with an implementation of toString() that identifies the source and target types.
+ */
+ private class CoercionWrapper<WS, WT> implements Coercion<WS, WT>
+ {
+ private final Coercion<WS, WT> coercion;
+
+ public CoercionWrapper(Coercion<WS, WT> coercion)
+ {
+ this.coercion = coercion;
+ }
+
+ @Override
+ public WT coerce(WS input)
+ {
+ return coercion.coerce(input);
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("%s --> %s", convert(sourceType), convert(targetType));
+ }
+ }
+
+ private String convert(Class type)
+ {
+ if (Void.class.equals(type))
+ return "null";
+
+ String name = PlasticUtils.toTypeName(type);
+
+ int dotx = name.lastIndexOf('.');
+
+ // Strip off a package name of "java.lang"
+
+ if (dotx > 0 && name.substring(0, dotx).equals("java.lang"))
+ return name.substring(dotx + 1);
+
+ return name;
+ }
+
+ /**
+ * Standard constructor, which defaults wrap to true.
+ */
+ public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
+ {
+ this(sourceType, targetType, coercion, true);
+ }
+
+ /**
+ * Convenience constructor to help with generics.
+ *
+ * @since 5.2.0
+ */
+ public static <S, T> CoercionTuple<S, T> create(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion)
+ {
+ return new CoercionTuple<S, T>(sourceType, targetType, coercion);
+ }
+
+ /**
+ * Internal-use constructor.
+ *
+ * @param sourceType
+ * the source (or input) type of the coercion, may be Void.class to indicate a coercion from null
+ * @param targetType
+ * the target (or output) type of the coercion
+ * @param coercion
+ * the object that performs the coercion
+ * @param wrap
+ * if true, the coercion is wrapped to provide a useful toString()
+ */
+ @SuppressWarnings("unchecked")
+ public CoercionTuple(Class<S> sourceType, Class<T> targetType, Coercion<S, T> coercion, boolean wrap)
+ {
+ assert sourceType != null;
+ assert targetType != null;
+ assert coercion != null;
+
+ this.sourceType = PlasticUtils.toWrapperType(sourceType);
+ this.targetType = PlasticUtils.toWrapperType(targetType);
+ this.coercion = wrap ? new CoercionWrapper<S, T>(coercion) : coercion;
+ }
+
+ @Override
+ public String toString()
+ {
+ return coercion.toString();
+ }
+
+ public Coercion<S, T> getCoercion()
+ {
+ return coercion;
+ }
+
+ public Class<S> getSourceType()
+ {
+ return sourceType;
+ }
+
+ public Class<T> getTargetType()
+ {
+ return targetType;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
new file mode 100644
index 0000000..ae542c5
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAccess.java
@@ -0,0 +1,77 @@
+// Copyright 2006, 2010, 2013 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.ioc.services;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * A wrapper around the JavaBean Introspector that allows more manageable access to JavaBean properties of objects.
+ * <p/>
+ * Only provides access to <em>simple</em> properties. Indexed properties are ignored.
+ * <p>
+ * Starting in Tapestry 5.2, public fields can now be accessed as if they were properly JavaBean properties. Where there
+ * is a name conflict, the true property will be favored over the field access.
+ */
+public interface PropertyAccess
+{
+ /**
+ * Reads the value of a property.
+ *
+ * @throws UnsupportedOperationException
+ * if the property is write only
+ * @throws IllegalArgumentException
+ * if property does not exist
+ */
+ Object get(Object instance, String propertyName);
+
+ /**
+ * Updates the value of a property.
+ *
+ * @throws UnsupportedOperationException
+ * if the property is read only
+ * @throws IllegalArgumentException
+ * if property does not exist
+ */
+ void set(Object instance, String propertyName, Object value);
+
+ /**
+ * Returns the annotation of a given property for the specified type if such an annotation is present, else null.
+ * A convenience over invoking {@link #getAdapter(Object)}.{@link ClassPropertyAdapter#getPropertyAdapter(String)}.{@link PropertyAdapter#getAnnotation(Class)}
+ *
+ * @param instance the object to read a value from
+ * @param propertyName the name of the property to read (case is ignored)
+ * @param annotationClass the type of annotation to return
+ * @throws IllegalArgumentException
+ * if property does not exist
+ *
+ * @since 5.4
+ */
+ Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass);
+
+ /**
+ * Returns the adapter for a particular object instance. A convienience over invoking {@link #getAdapter(Class)}.
+ */
+ ClassPropertyAdapter getAdapter(Object instance);
+
+ /**
+ * Returns the adapter used to access properties within the indicated class.
+ */
+ ClassPropertyAdapter getAdapter(Class forClass);
+
+ /**
+ * Discards all stored property access information, discarding all created class adapters.
+ */
+ void clearCache();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
new file mode 100644
index 0000000..947535e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/PropertyAdapter.java
@@ -0,0 +1,121 @@
+// Copyright 2006, 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.ioc.services;
+
+import org.apache.tapestry5.ioc.AnnotationProvider;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Provides access to a single property within a class. Acts as an {@link org.apache.tapestry5.ioc.AnnotationProvider};
+ * when searching for annotations, the read method (if present) is checked first, followed by the write method, followed
+ * by the underlying field (when the property name matches the field name).
+ * <p/>
+ * Starting in release 5.2, this property may actually be a public field. In 5.3, it may be a public static field.
+ *
+ * @see org.apache.tapestry5.ioc.services.ClassPropertyAdapter
+ */
+@SuppressWarnings("unchecked")
+public interface PropertyAdapter extends AnnotationProvider
+{
+ /**
+ * Returns the name of the property (or public field).
+ */
+ String getName();
+
+ /**
+ * Returns true if the property is readable (i.e., has a getter method or is a public field).
+ */
+ boolean isRead();
+
+ /**
+ * Returns the method used to read the property, or null if the property is not readable (or is a public field).
+ */
+ public Method getReadMethod();
+
+ /**
+ * Returns true if the property is writeable (i.e., has a setter method or is a non-final field).
+ */
+ boolean isUpdate();
+
+ /**
+ * Returns the method used to update the property, or null if the property is not writeable (or a public field).
+ */
+ public Method getWriteMethod();
+
+ /**
+ * Reads the property value.
+ *
+ * @param instance to read from
+ * @throws UnsupportedOperationException if the property is write only
+ */
+ Object get(Object instance);
+
+ /**
+ * Updates the property value. The provided value must not be null if the property type is primitive, and must
+ * otherwise be of the proper type.
+ *
+ * @param instance to update
+ * @param value new value for the property
+ * @throws UnsupportedOperationException if the property is read only
+ */
+ void set(Object instance, Object value);
+
+ /**
+ * Returns the type of the property.
+ */
+ Class getType();
+
+ /**
+ * Returns true if the return type of the read method is not the same as the property type. This can occur when the
+ * property has been defined using generics, in which case, the method's type may be Object when the property type
+ * is something more specific. This method is primarily used when generating runtime code related to the property.
+ */
+ boolean isCastRequired();
+
+ /**
+ * Returns the {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter} that provides access to other
+ * properties defined by the same class.
+ */
+ ClassPropertyAdapter getClassAdapter();
+
+ /**
+ * Returns the type of bean to which this property belongs. This is the same as
+ * {@link org.apache.tapestry5.ioc.services.ClassPropertyAdapter#getBeanType()}.
+ */
+ Class getBeanType();
+
+ /**
+ * Returns true if the property is actually a public field (possibly, a public static field).
+ *
+ * @since 5.2
+ */
+ boolean isField();
+
+ /**
+ * Returns the field if the property is a public field or null if the property is accessed via the read method.
+ *
+ * @since 5.2
+ */
+ Field getField();
+
+ /**
+ * The class in which the property (or public field) is defined.
+ *
+ * @since 5.2
+ */
+ Class getDeclaringClass();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java b/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
new file mode 100644
index 0000000..ec8eaad
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/services/TypeCoercer.java
@@ -0,0 +1,88 @@
+// Copyright 2006, 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.ioc.services;
+
+import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
+
+/**
+ * Makes use of {@link org.apache.tapestry5.ioc.services.Coercion}s to convert between an input value (of some specific
+ * type) and a desired output type. Smart about coercing, even if it requires multiple coercion steps (i.e., via an
+ * intermediate type, such as String).
+ */
+@UsesConfiguration(CoercionTuple.class)
+public interface TypeCoercer
+{
+ /**
+ * Performs a coercion from an input type to a desired output type. When the target type is a primitive, the actual
+ * conversion will be to the equivalent wrapper type. In some cases, the TypeCoercer will need to search for an
+ * appropriate coercion, and may even combine existing coercions to form new ones; in those cases, the results of
+ * the search are cached.
+ * <p/>
+ * The TypeCoercer also caches the results of a coercion search.
+ *
+ * @param <S>
+ * source type (input)
+ * @param <T>
+ * target type (output)
+ * @param input
+ * @param targetType
+ * defines the target type
+ * @return the coerced value
+ * @throws RuntimeException
+ * if the input can not be coerced
+ */
+ <S, T> T coerce(S input, Class<T> targetType);
+
+ /**
+ * Given a source and target type, computes the coercion that will be used.
+ * <p>
+ * Note: holding the returned coercion past the time when {@linkplain #clearCache() the cache is cleared} can cause
+ * a memory leak, especially in the context of live reloading (wherein holding a reference to a single class make
+ * keep an entire ClassLoader from being reclaimed).
+ *
+ * @since 5.2.0
+ * @param <S>
+ * source type (input)
+ * @param <T>
+ * target type (output)
+ * @param sourceType
+ * type to coerce from
+ * @param targetType
+ * defines the target type
+ * @return the coercion that will ultimately be used
+ */
+ <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType);
+
+ /**
+ * Used primarily inside test suites, this method performs the same steps as {@link #coerce(Object, Class)}, but
+ * returns a string describing the series of coercions, such as "Object --> String --> Long --> Integer".
+ *
+ * @param <S>
+ * source type (input)
+ * @param <T>
+ * target type (output)
+ * @param sourceType
+ * the source coercion type (use void.class for coercions from null)
+ * @param targetType
+ * defines the target type
+ * @return a string identifying the series of coercions, or the empty string if no coercion is necessary
+ */
+ <S, T> String explain(Class<S> sourceType, Class<T> targetType);
+
+ /**
+ * Clears cached information stored by the TypeCoercer.
+ */
+ void clearCache();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
new file mode 100644
index 0000000..c4c5c6d
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/AvailableValues.java
@@ -0,0 +1,87 @@
+// 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.ioc.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+
+/**
+ * Used (as part of a {@link UnknownValueException} to identify what available values
+ * are present.
+ *
+ * @since 5.2.0
+ */
+public class AvailableValues
+{
+ private final String valueType;
+
+ private final List<String> values;
+
+ /**
+ * @param valueType
+ * a word or phrase that describes what the values are such as "component types" or "service ids"
+ *@param values
+ * a set of objects defining the values; the values will be converted to strings and sorted into
+ * ascending order
+ */
+ public AvailableValues(String valueType, Collection<?> values)
+ {
+ this.valueType = valueType;
+ this.values = sortValues(values);
+ }
+
+ public AvailableValues(String valueType, Map<?, ?> map)
+ {
+ this(valueType, map.keySet());
+ }
+
+ private static List<String> sortValues(Collection<?> values)
+ {
+ List<String> result = CollectionFactory.newList();
+
+ for (Object v : values)
+ {
+ result.add(String.valueOf(v));
+ }
+
+ Collections.sort(result);
+
+ return Collections.unmodifiableList(result);
+ }
+
+ /** The type of value, i.e., "component types" or "service ids". */
+ public String getValueType()
+ {
+ return valueType;
+ }
+
+ /** The values, as strings, in sorted order. */
+ public List<String> getValues()
+ {
+ return values;
+ }
+
+ @Override
+ public String toString()
+ {
+ return String.format("AvailableValues[%s: %s]", valueType, InternalUtils.join(values));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
new file mode 100644
index 0000000..f5aff7e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/CaseInsensitiveMap.java
@@ -0,0 +1,499 @@
+// 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.ioc.util;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * An mapped collection where the keys are always strings and access to values is case-insensitive. The case of keys in
+ * the map is <em>maintained</em>, but on any access to a key (directly or indirectly), all key comparisons are
+ * performed in a case-insensitive manner. The map implementation is intended to support a reasonably finite number
+ * (dozens or hundreds, not thousands or millions of key/value pairs. Unlike HashMap, it is based on a sorted list of
+ * entries rather than hash bucket. It is also geared towards a largely static map, one that is created and then used
+ * without modification.
+ *
+ * @param <V> the type of value stored
+ */
+public class CaseInsensitiveMap<V> extends AbstractMap<String, V> implements Serializable
+{
+ private static final long serialVersionUID = 3362718337611953298L;
+
+ private static final int NULL_HASH = Integer.MIN_VALUE;
+
+ private static final int DEFAULT_SIZE = 20;
+
+ private static class CIMEntry<V> implements Map.Entry<String, V>, Serializable
+ {
+ private static final long serialVersionUID = 6713986085221148350L;
+
+ private String key;
+
+ private final int hashCode;
+
+ V value;
+
+ public CIMEntry(final String key, final int hashCode, V value)
+ {
+ this.key = key;
+ this.hashCode = hashCode;
+ this.value = value;
+ }
+
+ @Override
+ public String getKey()
+ {
+ return key;
+ }
+
+ @Override
+ public V getValue()
+ {
+ return value;
+ }
+
+ @Override
+ public V setValue(V value)
+ {
+ V result = this.value;
+
+ this.value = value;
+
+ return result;
+ }
+
+ /**
+ * Returns true if both keys are null, or if the provided key is the same as, or case-insensitively equal to,
+ * the entrie's key.
+ *
+ * @param key to compare against
+ * @return true if equal
+ */
+ @SuppressWarnings({ "StringEquality" })
+ boolean matches(String key)
+ {
+ return key == this.key || (key != null && key.equalsIgnoreCase(this.key));
+ }
+
+ boolean valueMatches(Object value)
+ {
+ return value == this.value || (value != null && value.equals(this.value));
+ }
+ }
+
+ private class EntrySetIterator implements Iterator
+ {
+ int expectedModCount = modCount;
+
+ int index;
+
+ int current = -1;
+
+ @Override
+ public boolean hasNext()
+ {
+ return index < size;
+ }
+
+ @Override
+ public Object next()
+ {
+ check();
+
+ if (index >= size) throw new NoSuchElementException();
+
+ current = index++;
+
+ return entries[current];
+ }
+
+ @Override
+ public void remove()
+ {
+ check();
+
+ if (current < 0) throw new NoSuchElementException();
+
+ new Position(current, true).remove();
+
+ expectedModCount = modCount;
+ }
+
+ private void check()
+ {
+ if (expectedModCount != modCount) throw new ConcurrentModificationException();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private class EntrySet extends AbstractSet
+ {
+ @Override
+ public Iterator iterator()
+ {
+ return new EntrySetIterator();
+ }
+
+ @Override
+ public int size()
+ {
+ return size;
+ }
+
+ @Override
+ public void clear()
+ {
+ CaseInsensitiveMap.this.clear();
+ }
+
+ @Override
+ public boolean contains(Object o)
+ {
+ if (!(o instanceof Map.Entry)) return false;
+
+ Map.Entry e = (Map.Entry) o;
+
+ Position position = select(e.getKey());
+
+ return position.isFound() && position.entry().valueMatches(e.getValue());
+ }
+
+ @Override
+ public boolean remove(Object o)
+ {
+ if (!(o instanceof Map.Entry)) return false;
+
+ Map.Entry e = (Map.Entry) o;
+
+ Position position = select(e.getKey());
+
+ if (position.isFound() && position.entry().valueMatches(e.getValue()))
+ {
+ position.remove();
+ return true;
+ }
+
+ return false;
+ }
+
+ }
+
+ private class Position
+ {
+ private final int cursor;
+
+ private final boolean found;
+
+ Position(int cursor, boolean found)
+ {
+ this.cursor = cursor;
+ this.found = found;
+ }
+
+ boolean isFound()
+ {
+ return found;
+ }
+
+ CIMEntry<V> entry()
+ {
+ return entries[cursor];
+ }
+
+ V get()
+ {
+ return found ? entries[cursor].value : null;
+ }
+
+ V remove()
+ {
+ if (!found) return null;
+
+ V result = entries[cursor].value;
+
+ // Remove the entry by shifting everything else down.
+
+ System.arraycopy(entries, cursor + 1, entries, cursor, size - cursor - 1);
+
+ // We shifted down, leaving one (now duplicate) entry behind.
+
+ entries[--size] = null;
+
+ // A structural change for sure
+
+ modCount++;
+
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ V put(String key, int hashCode, V newValue)
+ {
+ if (found)
+ {
+ CIMEntry<V> e = entries[cursor];
+
+ V result = e.value;
+
+ // Not a structural change, so no change to modCount
+
+ // Update the key (to maintain case). By definition, the hash code
+ // will not change.
+
+ e.key = key;
+ e.value = newValue;
+
+ return result;
+ }
+
+ // Not found, we're going to add it.
+
+ int newSize = size + 1;
+
+ if (newSize == entries.length)
+ {
+ // Time to expand!
+
+ int newCapacity = (size * 3) / 2 + 1;
+
+ CIMEntry<V>[] newEntries = new CIMEntry[newCapacity];
+
+ System.arraycopy(entries, 0, newEntries, 0, cursor);
+
+ System.arraycopy(entries, cursor, newEntries, cursor + 1, size - cursor);
+
+ entries = newEntries;
+ }
+ else
+ {
+ // Open up a space for the new entry
+
+ System.arraycopy(entries, cursor, entries, cursor + 1, size - cursor);
+ }
+
+ CIMEntry<V> newEntry = new CIMEntry<V>(key, hashCode, newValue);
+ entries[cursor] = newEntry;
+
+ size++;
+
+ // This is definately a structural change
+
+ modCount++;
+
+ return null;
+ }
+
+ }
+
+ // The list of entries. This is kept sorted by hash code. In some cases, there may be different
+ // keys with the same hash code in adjacent indexes.
+ private CIMEntry<V>[] entries;
+
+ private int size = 0;
+
+ // Used by iterators to check for concurrent modifications
+
+ private transient int modCount = 0;
+
+ private transient Set<Map.Entry<String, V>> entrySet;
+
+ public CaseInsensitiveMap()
+ {
+ this(DEFAULT_SIZE);
+ }
+
+ @SuppressWarnings("unchecked")
+ public CaseInsensitiveMap(int size)
+ {
+ entries = new CIMEntry[Math.max(size, 3)];
+ }
+
+ public CaseInsensitiveMap(Map<String, ? extends V> map)
+ {
+ this(map.size());
+
+ for (Map.Entry<String, ? extends V> entry : map.entrySet())
+ {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ @Override
+ public void clear()
+ {
+ for (int i = 0; i < size; i++)
+ entries[i] = null;
+
+ size = 0;
+ modCount++;
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return size == 0;
+ }
+
+ @Override
+ public int size()
+ {
+ return size;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public V put(String key, V value)
+ {
+ int hashCode = caseInsenitiveHashCode(key);
+
+ return select(key, hashCode).put(key, hashCode, value);
+ }
+
+ @Override
+ public boolean containsKey(Object key)
+ {
+ return select(key).isFound();
+ }
+
+ @Override
+ public V get(Object key)
+ {
+ return select(key).get();
+ }
+
+ @Override
+ public V remove(Object key)
+ {
+ return select(key).remove();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Set<Map.Entry<String, V>> entrySet()
+ {
+ if (entrySet == null) entrySet = new EntrySet();
+
+ return entrySet;
+ }
+
+ private Position select(Object key)
+ {
+ if (key == null || key instanceof String)
+ {
+ String keyString = (String) key;
+ return select(keyString, caseInsenitiveHashCode(keyString));
+ }
+
+ return new Position(0, false);
+ }
+
+ /**
+ * Searches the elements for the index of the indicated key and (case insensitive) hash code. Sets the _cursor and
+ * _found attributes.
+ */
+ private Position select(String key, int hashCode)
+ {
+ if (size == 0) return new Position(0, false);
+
+ int low = 0;
+ int high = size - 1;
+
+ int cursor;
+
+ while (low <= high)
+ {
+ cursor = (low + high) >> 1;
+
+ CIMEntry e = entries[cursor];
+
+ if (e.hashCode < hashCode)
+ {
+ low = cursor + 1;
+ continue;
+ }
+
+ if (e.hashCode > hashCode)
+ {
+ high = cursor - 1;
+ continue;
+ }
+
+ return tunePosition(key, hashCode, cursor);
+ }
+
+ return new Position(low, false);
+ }
+
+ /**
+ * select() has located a matching hashCode, but there's an outlying possibility that multiple keys share the same
+ * hashCode. Backup the cursor until we get to locate the initial hashCode match, then march forward until the key
+ * is located, or the hashCode stops matching.
+ *
+ * @param key
+ * @param hashCode
+ */
+ private Position tunePosition(String key, int hashCode, int cursor)
+ {
+ boolean found = false;
+
+ while (cursor > 0)
+ {
+ if (entries[cursor - 1].hashCode != hashCode) break;
+
+ cursor--;
+ }
+
+ while (true)
+ {
+ if (entries[cursor].matches(key))
+ {
+ found = true;
+ break;
+ }
+
+ // Advance to the next entry.
+
+ cursor++;
+
+ // If out of entries,
+ if (cursor >= size || entries[cursor].hashCode != hashCode) break;
+ }
+
+ return new Position(cursor, found);
+ }
+
+ static int caseInsenitiveHashCode(String input)
+ {
+ if (input == null) return NULL_HASH;
+
+ int length = input.length();
+ int hash = 0;
+
+ // This should end up more or less equal to input.toLowerCase().hashCode(), unless String
+ // changes its implementation. Let's hope this is reasonably fast.
+
+ for (int i = 0; i < length; i++)
+ {
+ int ch = input.charAt(i);
+
+ int caselessCh = Character.toLowerCase(ch);
+
+ hash = 31 * hash + caselessCh;
+ }
+
+ return hash;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
new file mode 100644
index 0000000..2feaeca
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/ExceptionUtils.java
@@ -0,0 +1,115 @@
+// Copyright 2008-2013 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.ioc.util;
+
+import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry5.ioc.services.PropertyAccess;
+
+/**
+ * Contains static methods useful for manipulating exceptions.
+ */
+public class ExceptionUtils
+{
+ /**
+ * Locates a particular type of exception, working its way via the cause property of each exception in the exception
+ * stack.
+ *
+ * @param t the outermost exception
+ * @param type the type of exception to search for
+ * @return the first exception of the given type, if found, or null
+ */
+ public static <T extends Throwable> T findCause(Throwable t, Class<T> type)
+ {
+ Throwable current = t;
+
+ while (current != null)
+ {
+ if (type.isInstance(current))
+ {
+ return type.cast(current);
+ }
+
+ // Not a match, work down.
+
+ current = current.getCause();
+ }
+
+ return null;
+ }
+
+ /**
+ * Locates a particular type of exception, working its way down via any property that returns some type of Exception.
+ * This is more expensive, but more accurate, than {@link #findCause(Throwable, Class)} as it works with older exceptions
+ * that do not properly implement the (relatively new) {@linkplain Throwable#getCause() cause property}.
+ *
+ * @param t the outermost exception
+ * @param type the type of exception to search for
+ * @param access used to access properties
+ * @return the first exception of the given type, if found, or null
+ */
+ public static <T extends Throwable> T findCause(Throwable t, Class<T> type, PropertyAccess access)
+ {
+ Throwable current = t;
+
+ while (current != null)
+ {
+ if (type.isInstance(current))
+ {
+ return type.cast(current);
+ }
+
+ Throwable next = null;
+
+ ClassPropertyAdapter adapter = access.getAdapter(current);
+
+ for (String name : adapter.getPropertyNames())
+ {
+
+ Object value = adapter.getPropertyAdapter(name).get(current);
+
+ if (value != null && value != current && value instanceof Throwable)
+ {
+ next = (Throwable) value;
+ break;
+ }
+ }
+
+ current = next;
+ }
+
+
+ return null;
+ }
+
+ /**
+ * Extracts the message from an exception. If the exception's message is null, returns the exceptions class name.
+ *
+ * @param exception
+ * to extract message from
+ * @return message or class name
+ * @since 5.4
+ */
+ public static String toMessage(Throwable exception)
+ {
+ assert exception != null;
+
+ String message = exception.getMessage();
+
+ if (message != null)
+ return message;
+
+ return exception.getClass().getName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java b/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
new file mode 100644
index 0000000..470b611
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/ioc/util/UnknownValueException.java
@@ -0,0 +1,47 @@
+// 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.ioc.util;
+
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+
+/**
+ * Special exception used when a value (typically from a map) is referenced that does not exist. Uses a
+ * {@link AvailableValues} object
+ * to track what the known values are.
+ *
+ * @since 5.2.0
+ */
+public class UnknownValueException extends TapestryException
+{
+ private final AvailableValues availableValues;
+
+ public UnknownValueException(String message, AvailableValues availableValues)
+ {
+ this(message, null, null, availableValues);
+ }
+
+ public UnknownValueException(String message, Object location, Throwable cause, AvailableValues availableValues)
+ {
+ super(message, location, cause);
+
+ this.availableValues = availableValues;
+ }
+
+ public AvailableValues getAvailableValues()
+ {
+ return availableValues;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/f963c7ab/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java b/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
new file mode 100644
index 0000000..77b028e
--- /dev/null
+++ b/commons/src/main/java/org/apache/tapestry5/services/InvalidationEventHub.java
@@ -0,0 +1,60 @@
+// Copyright 2006, 2007, 2008, 2011, 2012 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.services;
+
+import java.util.Map;
+
+/**
+ * An object which manages a list of {@link org.apache.tapestry5.services.InvalidationListener}s. There are multiple
+ * event hub services implementing this interface, each with a specific marker annotation; each can register listeners
+ * and fire events; these are based on the type of resource that has been invalidated. Tapestry has built-in support
+ * for:
+ * <dl>
+ * <dt>message catalog resources
+ * <dd>{@link org.apache.tapestry5.services.ComponentMessages} marker annotation
+ * <dt>component templates
+ * <dd>{@link org.apache.tapestry5.services.ComponentTemplates} marker annotation
+ * <dt>component classes
+ * <dd>{@link org.apache.tapestry5.services.ComponentClasses} marker annotation
+ * </dl>
+ * <p/>
+ * Starting in Tapestry 5.3, these services are disabled in production (it does nothing).
+ *
+ * @since 5.1.0.0
+ */
+public interface InvalidationEventHub
+{
+ /**
+ * Adds a listener, who needs to know when an underlying resource of a given category has changed (so that the
+ * receiver may discard any cached data that may have been invalidated). Does nothing in production mode.
+ *
+ * @deprecated in 5.4, use {@link #addInvalidationCallback(Runnable)} instead}
+ */
+ void addInvalidationListener(InvalidationListener listener);
+
+ /**
+ * Adds a callback that is invoked when an underlying tracked resource has changed. Does nothing in production mode.
+ *
+ * @since 5.4
+ */
+ void addInvalidationCallback(Runnable callback);
+
+ /**
+ * Adds a callback that clears the map.
+ *
+ * @since 5.4
+ */
+ void clearOnInvalidation(Map<?,?> map);
+}
[12/15] tapestry-5 git commit: Fourth pass creating the BeanModel and
Commons packages.
Posted by th...@apache.org.
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
deleted file mode 100644
index 9151381..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/OrderedConfiguration.java
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2006, 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.ioc;
-
-/**
- * Object passed into a service contributor method that allows the method provide contributed values to the service's
- * configuration.
- * <p/>
- * A service can <em>collect</em> contributions in three different ways:
- * <ul>
- * <li>As an un-ordered collection of values</li>
- * <li>As an ordered list of values (where each value has a unique id, pre-requisites and post-requisites)</li>
- * <li>As a map of keys and values
- * </ul>
- * <p/>
- * The service defines the <em>type</em> of contribution, in terms of a base class or service interface. Contributions
- * must be compatible with the type, or be {@linkplain org.apache.tapestry5.ioc.services.TypeCoercer coercable} to the type.
- *
- * @see org.apache.tapestry5.ioc.annotations.Contribute
- * @see org.apache.tapestry5.ioc.annotations.UsesConfiguration
- */
-public interface OrderedConfiguration<T>
-{
- /**
- * Adds an ordered object to a service's contribution. Each object has an id (which must be unique). Optionally,
- * pre-requisites (a list of ids that must precede this object) and post-requisites (ids that must follow) can be
- * provided.
- * <p/>
- * <p>If no constraints are supplied, then an implicit constraint is supplied: after the previously
- * contributed id <em>within the same contribution method</em>.
- *
- * @param id a unique id for the object; the id will be fully qualified with the contributing module's id
- * @param constraints used to order the object relative to other contributed objects
- * @param object to add to the service's configuration
- */
- void add(String id, T object, String... constraints);
-
- /**
- * Overrides a normally contributed object. Each override must match a single normally contributed object.
- *
- * @param id identifies object to override
- * @param object overriding object (may be null)
- * @param constraints constraints for the overridden object, replacing constraints for the original object (even if
- * omitted, in which case the override object will have no ordering constraints)
- * @since 5.1.0.0
- */
- void override(String id, T object, String... constraints);
-
- /**
- * Adds an ordered object by instantiating (with dependencies) the indicated class. When the configuration type is
- * an interface and the class to be contributed is a local file,
- * then a reloadable proxy for the class will be created and contributed.
- *
- * @param id of contribution (used for ordering)
- * @param clazz class to instantiate
- * @param constraints used to order the object relative to other contributed objects
- * @since 5.1.0.0
- */
- void addInstance(String id, Class<? extends T> clazz, String... constraints);
-
- /**
- * Instantiates an object and adds it as an override. When the configuration type is an interface and the class to
- * be contributed is a local file, then a reloadable proxy for the class will be created and contributed.
- *
- * @param id of object to override
- * @param clazz to instantiate
- * @param constraints constraints for the overridden object, replacing constraints for the original object (even if
- * omitted, in which case the override object will have no ordering constraints)
- * @since 5.1.0.0
- */
- void overrideInstance(String id, Class<? extends T> clazz, String... constraints);
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
deleted file mode 100644
index 2acfd0d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AccessableObjectAnnotationProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AccessibleObject;
-
-/**
- * Provides access to annotations of an accessable object such as a {@link java.lang.reflect.Method} or {@link
- * java.lang.reflect.Field}.
- */
-public class AccessableObjectAnnotationProvider implements AnnotationProvider
-{
- private final AccessibleObject object;
-
- public AccessableObjectAnnotationProvider(AccessibleObject object)
- {
- this.object = object;
- }
-
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return object.getAnnotation(annotationClass);
- }
-
- @Override
- public String toString()
- {
- return String.format("AnnotationProvider[%s]", object);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
deleted file mode 100644
index 49b0b15..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationProviderChain.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-
-import java.lang.annotation.Annotation;
-import java.util.List;
-
-/**
- * Chain of command for {@link org.apache.tapestry5.ioc.AnnotationProvider}.
- */
-public class AnnotationProviderChain implements AnnotationProvider
-{
- private final AnnotationProvider[] providers;
-
- public AnnotationProviderChain(AnnotationProvider[] providers)
- {
- this.providers = providers;
- }
-
- /**
- * Creates an AnnotationProvider from the list of providers. Returns either an {@link AnnotationProviderChain} or
- * the sole element in the list.
- */
- public static AnnotationProvider create(List<AnnotationProvider> providers)
- {
- int size = providers.size();
-
- if (size == 1) return providers.get(0);
-
- return new AnnotationProviderChain(providers.toArray(new AnnotationProvider[providers.size()]));
- }
-
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- for (AnnotationProvider p : providers)
- {
- T result = p.getAnnotation(annotationClass);
-
- if (result != null) return result;
- }
-
- return null;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
deleted file mode 100644
index af4bd7d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassPropertyAdapterImpl.java
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010, 2011, 2012 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.ioc.internal.services;
-
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
-
-import java.beans.PropertyDescriptor;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.GenericsUtils;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-
-public class ClassPropertyAdapterImpl implements ClassPropertyAdapter
-{
- private final Map<String, PropertyAdapter> adapters = newCaseInsensitiveMap();
-
- private final Class beanType;
-
- public ClassPropertyAdapterImpl(Class beanType, List<PropertyDescriptor> descriptors)
- {
- this.beanType = beanType;
-
- // lazy init
- Map<String, List<Method>> nonBridgeMethods = null;
-
- for (PropertyDescriptor pd : descriptors)
- {
- // Indexed properties will have a null propertyType (and a non-null
- // indexedPropertyType). We ignore indexed properties.
-
- final Class<?> thisPropertyType = pd.getPropertyType();
- if (thisPropertyType == null)
- continue;
-
- Method readMethod = pd.getReadMethod();
- Method writeMethod = pd.getWriteMethod();
-
- // TAP5-1493
- if (readMethod != null && readMethod.isBridge())
- {
- if (nonBridgeMethods == null)
- {
- nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
- }
- readMethod = findMethodWithSameNameAndParamCount(readMethod, nonBridgeMethods);
- }
-
- // TAP5-1548, TAP5-1885: trying to find a getter which Introspector missed
- if (readMethod == null) {
- final String prefix = thisPropertyType != boolean.class ? "get" : "is";
- try
- {
- Method method = beanType.getMethod(prefix + capitalize(pd.getName()));
- final Class<?> returnType = method.getReturnType();
- if (returnType.equals(thisPropertyType) || returnType.isInstance(thisPropertyType)) {
- readMethod = method;
- }
- }
- catch (SecurityException e) {
- // getter not usable.
- }
- catch (NoSuchMethodException e)
- {
- // getter doesn't exist.
- }
- }
-
- if (writeMethod != null && writeMethod.isBridge())
- {
- if (nonBridgeMethods == null)
- {
- nonBridgeMethods = groupNonBridgeMethodsByName(beanType);
- }
- writeMethod = findMethodWithSameNameAndParamCount(writeMethod, nonBridgeMethods);
- }
-
- // TAP5-1548, TAP5-1885: trying to find a setter which Introspector missed
- if (writeMethod == null) {
- try
- {
- Method method = beanType.getMethod("set" + capitalize(pd.getName()), pd.getPropertyType());
- final Class<?> returnType = method.getReturnType();
- if (returnType.equals(void.class)) {
- writeMethod = method;
- }
- }
- catch (SecurityException e) {
- // setter not usable.
- }
- catch (NoSuchMethodException e)
- {
- // setter doesn't exist.
- }
- }
-
- Class propertyType = readMethod == null ? thisPropertyType : GenericsUtils.extractGenericReturnType(
- beanType, readMethod);
-
- PropertyAdapter pa = new PropertyAdapterImpl(this, pd.getName(), propertyType, readMethod, writeMethod);
-
- adapters.put(pa.getName(), pa);
- }
-
- // Now, add any public fields (even if static) that do not conflict
-
- for (Field f : beanType.getFields())
- {
- String name = f.getName();
-
- if (!adapters.containsKey(name))
- {
- Class propertyType = GenericsUtils.extractGenericFieldType(beanType, f);
- PropertyAdapter pa = new PropertyAdapterImpl(this, name, propertyType, f);
-
- adapters.put(name, pa);
- }
- }
- }
-
- private static String capitalize(String name)
- {
- return Character.toUpperCase(name.charAt(0)) + name.substring(1);
- }
-
- /**
- * Find a replacement for the method (if one exists)
- * @param method A method
- * @param groupedMethods Methods mapped by name
- * @return A method from groupedMethods with the same name / param count
- * (default to providedmethod if none found)
- */
- private Method findMethodWithSameNameAndParamCount(Method method, Map<String, List<Method>> groupedMethods) {
- List<Method> methodGroup = groupedMethods.get(method.getName());
- if (methodGroup != null)
- {
- for (Method nonBridgeMethod : methodGroup)
- {
- if (nonBridgeMethod.getParameterTypes().length == method.getParameterTypes().length)
- {
- // return the non-bridge method with the same name / argument count
- return nonBridgeMethod;
- }
- }
- }
-
- // default to the provided method
- return method;
- }
-
- /**
- * Find all of the public methods that are not bridge methods and
- * group them by method name
- *
- * {@see Method#isBridge()}
- * @param type Bean type
- * @return
- */
- private Map<String, List<Method>> groupNonBridgeMethodsByName(Class type)
- {
- Map<String, List<Method>> methodGroupsByName = CollectionFactory.newMap();
- for (Method method : type.getMethods())
- {
- if (!method.isBridge())
- {
- List<Method> methodGroup = methodGroupsByName.get(method.getName());
- if (methodGroup == null)
- {
- methodGroup = CollectionFactory.newList();
- methodGroupsByName.put(method.getName(), methodGroup);
- }
- methodGroup.add(method);
- }
- }
- return methodGroupsByName;
- }
-
- @Override
- public Class getBeanType()
- {
- return beanType;
- }
-
- @Override
- public String toString()
- {
- String names = InternalUtils.joinSorted(adapters.keySet());
-
- return String.format("<ClassPropertyAdaptor %s: %s>", beanType.getName(), names);
- }
-
- @Override
- public List<String> getPropertyNames()
- {
- return InternalUtils.sortedKeys(adapters);
- }
-
- @Override
- public PropertyAdapter getPropertyAdapter(String name)
- {
- return adapters.get(name);
- }
-
- @Override
- public Object get(Object instance, String propertyName)
- {
- return adaptorFor(propertyName).get(instance);
- }
-
- @Override
- public void set(Object instance, String propertyName, Object value)
- {
- adaptorFor(propertyName).set(instance, value);
- }
-
- @Override
- public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) {
- return adaptorFor(propertyName).getAnnotation(annotationClass);
- }
-
- private PropertyAdapter adaptorFor(String name)
- {
- PropertyAdapter pa = adapters.get(name);
-
- if (pa == null)
- throw new IllegalArgumentException(ServiceMessages.noSuchProperty(beanType, name));
-
- return pa;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
deleted file mode 100644
index 4a5dece..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CompoundCoercion.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2006, 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.services.Coercion;
-
-/**
- * Combines two coercions to create a coercion through an intermediate type.
- *
- * @param <S> The source (input) type
- * @param <I> The intermediate type
- * @param <T> The target (output) type
- */
-public class CompoundCoercion<S, I, T> implements Coercion<S, T>
-{
- private final Coercion<S, I> op1;
-
- private final Coercion<I, T> op2;
-
- public CompoundCoercion(Coercion<S, I> op1, Coercion<I, T> op2)
- {
- this.op1 = op1;
- this.op2 = op2;
- }
-
- @Override
- public T coerce(S input)
- {
- // Run the input through the first operation (S --> I), then run the result of that through
- // the second operation (I --> T).
-
- I intermediate = op1.coerce(input);
-
- return op2.coerce(intermediate);
- }
-
- @Override
- public String toString()
- {
- return String.format("%s, %s", op1, op2);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
deleted file mode 100644
index 8ebdede..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticClassListenerLogger.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 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.ioc.internal.services;
-
-import org.apache.tapestry5.plastic.ClassType;
-import org.apache.tapestry5.plastic.PlasticClassEvent;
-import org.apache.tapestry5.plastic.PlasticClassListener;
-import org.slf4j.Logger;
-import org.slf4j.Marker;
-import org.slf4j.MarkerFactory;
-
-public class PlasticClassListenerLogger implements PlasticClassListener
-{
- private final Logger logger;
-
- public PlasticClassListenerLogger(Logger logger)
- {
- this.logger = logger;
- }
-
- @Override
- public void classWillLoad(PlasticClassEvent event)
- {
- if (logger.isDebugEnabled())
- {
- Marker marker = MarkerFactory.getMarker(event.getPrimaryClassName());
-
- String extendedClassName = event.getType() == ClassType.PRIMARY ? event.getPrimaryClassName() : String
- .format("%s (%s for %s)", event.getClassName(), event.getType(), event.getPrimaryClassName());
-
- logger.debug(marker,
- String.format("Loading class %s:\n%s", extendedClassName, event.getDissasembledBytecode()));
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
deleted file mode 100644
index 112e29d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright 2011, 2012 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.ioc.internal.services;
-
-import org.apache.tapestry5.internal.plastic.PlasticInternalUtils;
-import org.apache.tapestry5.internal.plastic.asm.Type;
-import org.apache.tapestry5.internal.plastic.asm.tree.*;
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.ObjectCreator;
-import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
-import org.apache.tapestry5.plastic.*;
-import org.slf4j.Logger;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Map;
-
-public class PlasticProxyFactoryImpl implements PlasticProxyFactory
-{
- public static final String INTERNAL_GET_DELEGATE = "_____internalGetDelegate_DONT_CALL_THIS_METHOD_____";
-
- private final PlasticManager manager;
-
- private final Map<String, Location> memberToLocation = CollectionFactory.newConcurrentMap();
-
- public PlasticProxyFactoryImpl(ClassLoader parentClassLoader, Logger logger)
- {
- this(PlasticManager.withClassLoader(parentClassLoader).create(), logger);
- }
-
- public PlasticProxyFactoryImpl(PlasticManager manager, Logger logger)
- {
- assert manager != null;
-
- this.manager = manager;
-
- if (logger != null)
- {
- manager.addPlasticClassListener(new PlasticClassListenerLogger(logger));
- }
- }
-
- @Override
- public ClassLoader getClassLoader()
- {
- return manager.getClassLoader();
- }
-
- @Override
- public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback)
- {
- return manager.createProxy(interfaceType, implementationType, callback);
- }
-
- @Override
- public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
- {
- return manager.createProxy(interfaceType, callback);
- }
-
-
- @Override
- public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType,
- Class<? extends T> implementationType)
- {
- return manager.createProxyTransformation(interfaceType, implementationType);
- }
-
- @Override
- public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType)
- {
- return createProxyTransformation(interfaceType, null);
- }
-
- @Override
- public <T> T createProxy(final Class<T> interfaceType, final ObjectCreator<T> creator, final String description)
- { return createProxy(interfaceType, null, creator, description);
- }
-
- @Override
- public <T> T createProxy(final Class<T> interfaceType, final Class<? extends T> implementationType,
- final ObjectCreator<T> creator, final String description)
- {
- assert creator != null;
- assert InternalUtils.isNonBlank(description);
-
- ClassInstantiator<T> instantiator = createProxy(interfaceType, implementationType, new PlasticClassTransformer()
- {
- @Override
- public void transform(PlasticClass plasticClass)
- {
- final PlasticField objectCreatorField = plasticClass.introduceField(ObjectCreator.class, "creator")
- .inject(creator);
-
- final String interfaceTypeName = interfaceType.getName();
- PlasticMethod delegateMethod = plasticClass.introducePrivateMethod(interfaceTypeName, "delegate",
- null, null);
-
- final InstructionBuilderCallback returnCreateObject = new InstructionBuilderCallback()
- {
- @Override
- public void doBuild(InstructionBuilder builder)
- {
- builder.loadThis().getField(objectCreatorField);
- builder.invoke(ObjectCreator.class, Object.class, "createObject");
- builder.checkcast(interfaceType).returnResult();
- }
- };
-
- delegateMethod.changeImplementation(returnCreateObject);
-
- for (Method method : interfaceType.getMethods())
- {
- plasticClass.introduceMethod(method).delegateTo(delegateMethod);
- }
-
- // TA5-2235
- MethodDescription getDelegateMethodDescription =
- new MethodDescription(interfaceType.getName(), INTERNAL_GET_DELEGATE);
- plasticClass.introduceMethod(getDelegateMethodDescription, returnCreateObject);
-
- plasticClass.addToString(description);
-
- }
- });
-
- return interfaceType.cast(instantiator.newInstance());
- }
-
- private ClassNode readClassNode(Class clazz)
- {
- byte[] bytecode = PlasticInternalUtils.readBytecodeForClass(manager.getClassLoader(), clazz.getName(), false);
-
- return bytecode == null ? null : PlasticInternalUtils.convertBytecodeToClassNode(bytecode);
- }
-
- @Override
- public Location getMethodLocation(final Method method)
- {
- ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
- {
- @Override
- public String createObject()
- {
- return InternalUtils.asString(method);
- }
- };
-
- return getMemberLocation(method, method.getName(), Type.getMethodDescriptor(method),
- descriptionCreator);
- }
-
- @Override
- public Location getConstructorLocation(final Constructor constructor)
- {
- ObjectCreator<String> descriptionCreator = new ObjectCreator<String>()
- {
- @Override
- public String createObject()
- {
- StringBuilder builder = new StringBuilder(constructor.getDeclaringClass().getName()).append("(");
- String sep = "";
-
- for (Class parameterType : constructor.getParameterTypes())
- {
- builder.append(sep);
- builder.append(parameterType.getSimpleName());
-
- sep = ", ";
- }
-
- builder.append(")");
-
- return builder.toString();
- }
- };
-
- return getMemberLocation(constructor, "<init>", Type.getConstructorDescriptor(constructor),
- descriptionCreator);
- }
-
- @Override
- public void clearCache()
- {
- memberToLocation.clear();
- }
-
-
- public Location getMemberLocation(Member member, String methodName, String memberTypeDesc, ObjectCreator<String> textDescriptionCreator)
- {
- String className = member.getDeclaringClass().getName();
-
- String key = className + ":" + methodName + ":" + memberTypeDesc;
-
- Location location = memberToLocation.get(key);
-
- if (location == null)
- {
- location = constructMemberLocation(member, methodName, memberTypeDesc, textDescriptionCreator.createObject());
-
- memberToLocation.put(key, location);
- }
-
- return location;
-
- }
-
- private Location constructMemberLocation(Member member, String methodName, String memberTypeDesc, String textDescription)
- {
-
- ClassNode classNode = readClassNode(member.getDeclaringClass());
-
- if (classNode == null)
- {
- throw new RuntimeException(String.format("Unable to read class file for %s (to gather line number information).",
- textDescription));
- }
-
- for (MethodNode mn : (List<MethodNode>) classNode.methods)
- {
- if (mn.name.equals(methodName) && mn.desc.equals(memberTypeDesc))
- {
- int lineNumber = findFirstLineNumber(mn.instructions);
-
- // If debugging info is not available, we may lose the line number data, in which case,
- // just generate the Location from the textDescription.
-
- if (lineNumber < 1)
- {
- break;
- }
-
- String description = String.format("%s (at %s:%d)", textDescription, classNode.sourceFile, lineNumber);
-
- return new StringLocation(description, lineNumber);
- }
- }
-
- // Didn't find it. Odd.
-
- return new StringLocation(textDescription, 0);
- }
-
- private int findFirstLineNumber(InsnList instructions)
- {
- for (AbstractInsnNode node = instructions.getFirst(); node != null; node = node.getNext())
- {
- if (node instanceof LineNumberNode)
- {
- return ((LineNumberNode) node).line;
- }
- }
-
- return -1;
- }
-
- @Override
- public void addPlasticClassListener(PlasticClassListener listener)
- {
- manager.addPlasticClassListener(listener);
- }
-
- @Override
- public void removePlasticClassListener(PlasticClassListener listener)
- {
- manager.removePlasticClassListener(listener);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
deleted file mode 100644
index 8dd1e02..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAccessImpl.java
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright 2006, 2007, 2008, 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.ioc.internal.services;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAccess;
-
-@SuppressWarnings("unchecked")
-public class PropertyAccessImpl implements PropertyAccess
-{
- private final Map<Class, ClassPropertyAdapter> adapters = CollectionFactory.newConcurrentMap();
-
- @Override
- public Object get(Object instance, String propertyName)
- {
- return getAdapter(instance).get(instance, propertyName);
- }
-
- @Override
- public void set(Object instance, String propertyName, Object value)
- {
- getAdapter(instance).set(instance, propertyName, value);
- }
-
- @Override
- public Annotation getAnnotation(Object instance, String propertyName, Class<? extends Annotation> annotationClass) {
- return getAdapter(instance).getAnnotation(instance, propertyName, annotationClass);
- }
-
-
- /**
- * Clears the cache of adapters and asks the {@link Introspector} to clear its cache.
- */
- @Override
- public synchronized void clearCache()
- {
- adapters.clear();
-
- Introspector.flushCaches();
- }
-
- @Override
- public ClassPropertyAdapter getAdapter(Object instance)
- {
- return getAdapter(instance.getClass());
- }
-
- @Override
- public ClassPropertyAdapter getAdapter(Class forClass)
- {
- ClassPropertyAdapter result = adapters.get(forClass);
-
- if (result == null)
- {
- result = buildAdapter(forClass);
- adapters.put(forClass, result);
- }
-
- return result;
- }
-
- /**
- * Builds a new adapter and updates the _adapters cache. This not only guards access to the adapter cache, but also
- * serializes access to the Java Beans Introspector, which is not thread safe. In addition, handles the case where
- * the class in question is an interface, accumulating properties inherited from super-classes.
- */
- private synchronized ClassPropertyAdapter buildAdapter(Class forClass)
- {
- // In some race conditions, we may hit this method for the same class multiple times.
- // We just let it happen, replacing the old ClassPropertyAdapter with a new one.
-
- try
- {
- BeanInfo info = Introspector.getBeanInfo(forClass);
-
- List<PropertyDescriptor> descriptors = CollectionFactory.newList();
-
- addAll(descriptors, info.getPropertyDescriptors());
-
- // TAP5-921 - Introspector misses interface methods not implemented in an abstract class
- if (forClass.isInterface() || Modifier.isAbstract(forClass.getModifiers()) )
- addPropertiesFromExtendedInterfaces(forClass, descriptors);
-
- addPropertiesFromScala(forClass, descriptors);
-
- return new ClassPropertyAdapterImpl(forClass, descriptors);
- }
- catch (Throwable ex)
- {
- throw new RuntimeException(ex);
- }
- }
-
- private <T> void addAll(List<T> list, T[] array)
- {
- list.addAll(Arrays.asList(array));
- }
-
- private void addPropertiesFromExtendedInterfaces(Class forClass, List<PropertyDescriptor> descriptors)
- throws IntrospectionException
- {
- LinkedList<Class> queue = CollectionFactory.newLinkedList();
-
- // Seed the queue
- addAll(queue, forClass.getInterfaces());
-
- while (!queue.isEmpty())
- {
- Class c = queue.removeFirst();
-
- BeanInfo info = Introspector.getBeanInfo(c);
-
- // Duplicates occur and are filtered out in ClassPropertyAdapter which stores
- // a property name to descriptor map.
- addAll(descriptors, info.getPropertyDescriptors());
- addAll(queue, c.getInterfaces());
- }
- }
-
- private void addPropertiesFromScala(Class forClass, List<PropertyDescriptor> descriptors)
- throws IntrospectionException
- {
- for (Method method : forClass.getMethods())
- {
- addPropertyIfScalaGetterMethod(forClass, descriptors, method);
- }
- }
-
- private void addPropertyIfScalaGetterMethod(Class forClass, List<PropertyDescriptor> descriptors, Method method)
- throws IntrospectionException
- {
- if (!isScalaGetterMethod(method))
- return;
-
- PropertyDescriptor propertyDescriptor = new PropertyDescriptor(method.getName(), forClass, method.getName(),
- null);
-
- // found a getter, looking for the setter now
- try
- {
- Method setterMethod = findScalaSetterMethod(forClass, method);
-
- propertyDescriptor.setWriteMethod(setterMethod);
- }
- catch (NoSuchMethodException e)
- {
- // ignore
- }
-
- // check if the same property was already discovered with java bean accessors
-
- addScalaPropertyIfNoJavaBeansProperty(descriptors, propertyDescriptor, method);
- }
-
- private void addScalaPropertyIfNoJavaBeansProperty(List<PropertyDescriptor> descriptors,
- PropertyDescriptor propertyDescriptor, Method getterMethod)
- {
- boolean found = false;
-
- for (PropertyDescriptor currentPropertyDescriptor : descriptors)
- {
- if (currentPropertyDescriptor.getName().equals(getterMethod.getName()))
- {
- found = true;
-
- break;
- }
- }
-
- if (!found)
- descriptors.add(propertyDescriptor);
- }
-
- private Method findScalaSetterMethod(Class forClass, Method getterMethod) throws NoSuchMethodException
- {
- return forClass.getMethod(getterMethod.getName() + "_$eq", getterMethod.getReturnType());
- }
-
- private boolean isScalaGetterMethod(Method method)
- {
- try
- {
- return Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0
- && !method.getReturnType().equals(Void.TYPE)
- && method.getDeclaringClass().getDeclaredField(method.getName()) != null;
- }
- catch (NoSuchFieldException ex)
- {
- return false;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
deleted file mode 100644
index 97685ef..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PropertyAdapterImpl.java
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2006-2013 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.AnnotationProvider;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
-import org.apache.tapestry5.ioc.services.PropertyAdapter;
-import org.apache.tapestry5.ioc.util.ExceptionUtils;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.*;
-import java.util.List;
-
-public class PropertyAdapterImpl implements PropertyAdapter
-{
- private final ClassPropertyAdapter classAdapter;
-
- private final String name;
-
- private final Method readMethod;
-
- private final Method writeMethod;
-
- private final Class type;
-
- private final boolean castRequired;
-
- // Synchronized by this; lazily initialized
- private AnnotationProvider annotationProvider;
-
- private final Field field;
-
- private final Class declaringClass;
-
- PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Method readMethod,
- Method writeMethod)
- {
- this.classAdapter = classAdapter;
- this.name = name;
- this.type = type;
-
- this.readMethod = readMethod;
- this.writeMethod = writeMethod;
-
- declaringClass = readMethod != null ? readMethod.getDeclaringClass() : writeMethod.getDeclaringClass();
-
- castRequired = readMethod != null && readMethod.getReturnType() != type;
-
- field = null;
- }
-
- PropertyAdapterImpl(ClassPropertyAdapter classAdapter, String name, Class type, Field field)
- {
- this.classAdapter = classAdapter;
- this.name = name;
- this.type = type;
-
- this.field = field;
-
- declaringClass = field.getDeclaringClass();
-
- castRequired = field.getType() != type;
-
- readMethod = null;
- writeMethod = null;
- }
-
- @Override
- public String getName()
- {
- return name;
- }
-
- @Override
- public Method getReadMethod()
- {
- return readMethod;
- }
-
- @Override
- public Class getType()
- {
- return type;
- }
-
- @Override
- public Method getWriteMethod()
- {
- return writeMethod;
- }
-
- @Override
- public boolean isRead()
- {
- return field != null || readMethod != null;
- }
-
- @Override
- public boolean isUpdate()
- {
- return writeMethod != null || (field != null && !isFinal(field));
- }
-
- private boolean isFinal(Member member)
- {
- return Modifier.isFinal(member.getModifiers());
- }
-
- @Override
- public Object get(Object instance)
- {
- if (field == null && readMethod == null)
- {
- throw new UnsupportedOperationException(String.format("Class %s does not provide an accessor ('getter') method for property '%s'.", toClassName(instance), name));
- }
-
- Throwable fail;
-
- try
- {
- if (field == null)
- return readMethod.invoke(instance);
- else
- return field.get(instance);
- } catch (InvocationTargetException ex)
- {
- fail = ex.getTargetException();
- } catch (Exception ex)
- {
- fail = ex;
- }
-
- throw new RuntimeException(ServiceMessages.readFailure(name, instance, fail), fail);
- }
-
- @Override
- public void set(Object instance, Object value)
- {
- if (field == null && writeMethod == null)
- {
- throw new UnsupportedOperationException(String.format("Class %s does not provide a mutator ('setter') method for property '%s'.",
- toClassName(instance),
- name
- ));
- }
-
- Throwable fail;
-
- try
- {
- if (field == null)
- writeMethod.invoke(instance, value);
- else
- field.set(instance, value);
-
- return;
- } catch (InvocationTargetException ex)
- {
- fail = ex.getTargetException();
- } catch (Exception ex)
- {
- fail = ex;
- }
-
- throw new RuntimeException(String.format("Error updating property '%s' of %s: %s",
- name, toClassName(instance),
- ExceptionUtils.toMessage(fail)), fail);
- }
-
- private String toClassName(Object instance)
- {
- return instance == null ? "<null>" : instance.getClass().getName();
- }
-
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
- {
- return getAnnnotationProvider().getAnnotation(annotationClass);
- }
-
- /**
- * Creates (as needed) the annotation provider for this property.
- */
- private synchronized AnnotationProvider getAnnnotationProvider()
- {
- if (annotationProvider == null)
- {
- List<AnnotationProvider> providers = CollectionFactory.newList();
-
- if (readMethod != null)
- providers.add(new AccessableObjectAnnotationProvider(readMethod));
-
- if (writeMethod != null)
- providers.add(new AccessableObjectAnnotationProvider(writeMethod));
-
- // There's an assumption here, that the fields match the property name (we ignore case
- // which leads to a manageable ambiguity) and that the field and the getter/setter
- // are in the same class (i.e., that we don't have a getter exposing a protected field inherted
- // from a base class, or some other oddity).
-
- Class cursor = getBeanType();
-
- out:
- while (cursor != null)
- {
- for (Field f : cursor.getDeclaredFields())
- {
- if (f.getName().equalsIgnoreCase(name))
- {
- providers.add(new AccessableObjectAnnotationProvider(f));
-
- break out;
- }
- }
-
- cursor = cursor.getSuperclass();
- }
-
- annotationProvider = AnnotationProviderChain.create(providers);
- }
-
- return annotationProvider;
- }
-
- @Override
- public boolean isCastRequired()
- {
- return castRequired;
- }
-
- @Override
- public ClassPropertyAdapter getClassAdapter()
- {
- return classAdapter;
- }
-
- @Override
- public Class getBeanType()
- {
- return classAdapter.getBeanType();
- }
-
- @Override
- public boolean isField()
- {
- return field != null;
- }
-
- @Override
- public Field getField()
- {
- return field;
- }
-
- @Override
- public Class getDeclaringClass()
- {
- return declaringClass;
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
deleted file mode 100644
index e92ef2d..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ServiceMessages.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2006, 2007, 2011, 2012 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.Messages;
-import org.apache.tapestry5.ioc.internal.util.MessagesImpl;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-public class ServiceMessages
-{
- private final static Messages MESSAGES = MessagesImpl.forClass(ServiceMessages.class);
-
- private ServiceMessages()
- {
- }
-
- public static String noSuchProperty(Class clazz, String propertyName)
- {
- return MESSAGES.format("no-such-property", clazz.getName(), propertyName);
- }
-
-
- public static String readFailure(String propertyName, Object instance, Throwable cause)
- {
- return MESSAGES.format("read-failure", propertyName, instance, cause);
- }
-
- public static String propertyTypeMismatch(String propertyName, Class sourceClass, Class propertyType,
- Class expectedType)
- {
- return MESSAGES.format("property-type-mismatch", propertyName, sourceClass.getName(), propertyType.getName(),
- expectedType.getName());
- }
-
- public static String shutdownListenerError(Object listener, Throwable cause)
- {
- return MESSAGES.format("shutdown-listener-error", listener, cause);
- }
-
- public static String failedCoercion(Object input, Class targetType, Coercion coercion, Throwable cause)
- {
- return MESSAGES.format("failed-coercion", String.valueOf(input), PlasticUtils.toTypeName(targetType),
- coercion, cause);
- }
-
- public static String registryShutdown(String serviceId)
- {
- return MESSAGES.format("registry-shutdown", serviceId);
- }
-
- public static String serviceBuildFailure(String serviceId, Throwable cause)
- {
- return MESSAGES.format("service-build-failure", serviceId, cause);
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
deleted file mode 100644
index 0769b7e..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/StringLocation.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.ioc.internal.services;
-
-import org.apache.tapestry5.ioc.Location;
-import org.apache.tapestry5.ioc.Resource;
-
-/**
- * Implementation of {@link Location} used when the underlying resource isn't really known.
- */
-public final class StringLocation implements Location
-{
- private final String description;
-
- private final int line;
-
- public StringLocation(String description, int line)
- {
- this.description = description;
- this.line = line;
- }
-
- @Override
- public String toString()
- {
- return description;
- }
-
- /**
- * Returns 0.
- */
- @Override
- public int getColumn()
- {
- return 0;
- }
-
- @Override
- public int getLine()
- {
- return line;
- }
-
- /**
- * Returns null; we don't know where the file really is (it's probably a class on the class path).
- */
- @Override
- public Resource getResource()
- {
- return null;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
deleted file mode 100644
index 46f1c0a..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImpl.java
+++ /dev/null
@@ -1,508 +0,0 @@
-// Copyright 2006, 2007, 2008, 2010, 2012 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.ioc.internal.services;
-
-import org.apache.tapestry5.func.F;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.internal.util.InheritanceSearch;
-import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.internal.util.LockSupport;
-import org.apache.tapestry5.ioc.services.Coercion;
-import org.apache.tapestry5.ioc.services.CoercionTuple;
-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.util.StringToEnumCoercion;
-
-import java.util.*;
-
-@SuppressWarnings("all")
-public class TypeCoercerImpl extends LockSupport implements TypeCoercer
-{
- // Constructed from the service's configuration.
-
- private final Map<Class, List<CoercionTuple>> sourceTypeToTuple = CollectionFactory.newMap();
-
- /**
- * A coercion to a specific target type. Manages a cache of coercions to specific types.
- */
- private class TargetCoercion
- {
- private final Class type;
-
- private final Map<Class, Coercion> cache = CollectionFactory.newConcurrentMap();
-
- TargetCoercion(Class type)
- {
- this.type = type;
- }
-
- void clearCache()
- {
- cache.clear();
- }
-
- Object coerce(Object input)
- {
- Class sourceType = input != null ? input.getClass() : Void.class;
-
- if (type.isAssignableFrom(sourceType))
- {
- return input;
- }
-
- Coercion c = getCoercion(sourceType);
-
- try
- {
- return type.cast(c.coerce(input));
- } catch (Exception ex)
- {
- throw new RuntimeException(ServiceMessages.failedCoercion(input, type, c, ex), ex);
- }
- }
-
- String explain(Class sourceType)
- {
- return getCoercion(sourceType).toString();
- }
-
- private Coercion getCoercion(Class sourceType)
- {
- Coercion c = cache.get(sourceType);
-
- if (c == null)
- {
- c = findOrCreateCoercion(sourceType, type);
- cache.put(sourceType, c);
- }
-
- return c;
- }
- }
-
- /**
- * Map from a target type to a TargetCoercion for that type.
- */
- private final Map<Class, TargetCoercion> typeToTargetCoercion = new WeakHashMap<Class, TargetCoercion>();
-
- private static final Coercion NO_COERCION = new Coercion<Object, Object>()
- {
- @Override
- public Object coerce(Object input)
- {
- return input;
- }
- };
-
- private static final Coercion COERCION_NULL_TO_OBJECT = new Coercion<Void, Object>()
- {
- @Override
- public Object coerce(Void input)
- {
- return null;
- }
-
- @Override
- public String toString()
- {
- return "null --> null";
- }
- };
-
- public TypeCoercerImpl(Collection<CoercionTuple> tuples)
- {
- for (CoercionTuple tuple : tuples)
- {
- Class key = tuple.getSourceType();
-
- InternalUtils.addToMapList(sourceTypeToTuple, key, tuple);
- }
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Object coerce(Object input, Class targetType)
- {
- assert targetType != null;
-
- Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-
- if (effectiveTargetType.isInstance(input))
- {
- return input;
- }
-
-
- return getTargetCoercion(effectiveTargetType).coerce(input);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <S, T> Coercion<S, T> getCoercion(Class<S> sourceType, Class<T> targetType)
- {
- assert sourceType != null;
- assert targetType != null;
-
- Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
- Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
-
- if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
- {
- return NO_COERCION;
- }
-
- return getTargetCoercion(effectiveTargetType).getCoercion(effectiveSourceType);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <S, T> String explain(Class<S> sourceType, Class<T> targetType)
- {
- assert sourceType != null;
- assert targetType != null;
-
- Class effectiveTargetType = PlasticUtils.toWrapperType(targetType);
- Class effectiveSourceType = PlasticUtils.toWrapperType(sourceType);
-
- // Is a coercion even necessary? Not if the target type is assignable from the
- // input value.
-
- if (effectiveTargetType.isAssignableFrom(effectiveSourceType))
- {
- return "";
- }
-
- return getTargetCoercion(effectiveTargetType).explain(effectiveSourceType);
- }
-
- private TargetCoercion getTargetCoercion(Class targetType)
- {
- try
- {
- acquireReadLock();
-
- TargetCoercion tc = typeToTargetCoercion.get(targetType);
-
- return tc != null ? tc : createAndStoreNewTargetCoercion(targetType);
- } finally
- {
- releaseReadLock();
- }
- }
-
- private TargetCoercion createAndStoreNewTargetCoercion(Class targetType)
- {
- try
- {
- upgradeReadLockToWriteLock();
-
- // Inner check since some other thread may have beat us to it.
-
- TargetCoercion tc = typeToTargetCoercion.get(targetType);
-
- if (tc == null)
- {
- tc = new TargetCoercion(targetType);
- typeToTargetCoercion.put(targetType, tc);
- }
-
- return tc;
- } finally
- {
- downgradeWriteLockToReadLock();
- }
- }
-
- @Override
- public void clearCache()
- {
- try
- {
- acquireReadLock();
-
- // There's no need to clear the typeToTargetCoercion map, as it is a WeakHashMap and
- // will release the keys for classes that are no longer in existence. On the other hand,
- // there's likely all sorts of references to unloaded classes inside each TargetCoercion's
- // individual cache, so clear all those.
-
- for (TargetCoercion tc : typeToTargetCoercion.values())
- {
- // Can tc ever be null?
-
- tc.clearCache();
- }
- } finally
- {
- releaseReadLock();
- }
- }
-
- /**
- * Here's the real meat; we do a search of the space to find coercions, or a system of
- * coercions, that accomplish
- * the desired coercion.
- * <p/>
- * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance lists could be
- * cached. Further, there's probably more ways to early prune the search. However, even with dozens or perhaps
- * hundreds of tuples, I suspect the search will still grind to a conclusion quickly.
- * <p/>
- * The order of operations should help ensure that the most efficient tuple chain is located. If you think about how
- * tuples are added to the queue, there are two factors: size (the number of steps in the coercion) and
- * "class distance" (that is, number of steps up the inheritance hiearchy). All the appropriate 1 step coercions
- * will be considered first, in class distance order. Along the way, we'll queue up all the 2 step coercions, again
- * in class distance order. By the time we reach some of those, we'll have begun queueing up the 3 step coercions, and
- * so forth, until we run out of input tuples we can use to fabricate multi-step compound coercions, or reach a
- * final response.
- * <p/>
- * This does create a good number of short lived temporary objects (the compound tuples), but that's what the GC is
- * really good at.
- *
- * @param sourceType
- * @param targetType
- * @return coercer from sourceType to targetType
- */
- @SuppressWarnings("unchecked")
- private Coercion findOrCreateCoercion(Class sourceType, Class targetType)
- {
- if (sourceType == Void.class)
- {
- return searchForNullCoercion(targetType);
- }
-
- // These are instance variables because this method may be called concurrently.
- // On a true race, we may go to the work of seeking out and/or fabricating
- // a tuple twice, but it's more likely that different threads are looking
- // for different source/target coercions.
-
- Set<CoercionTuple> consideredTuples = CollectionFactory.newSet();
- LinkedList<CoercionTuple> queue = CollectionFactory.newLinkedList();
-
- seedQueue(sourceType, targetType, consideredTuples, queue);
-
- while (!queue.isEmpty())
- {
- CoercionTuple tuple = queue.removeFirst();
-
- // If the tuple results in a value type that is assignable to the desired target type,
- // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
- // "quality" (how close is the tuple target type to the desired target type). Cost
- // is currently implicit, as compound tuples are stored deeper in the queue,
- // so simpler coercions will be located earlier.
-
- Class tupleTargetType = tuple.getTargetType();
-
- if (targetType.isAssignableFrom(tupleTargetType))
- {
- return tuple.getCoercion();
- }
-
- // So .. this tuple doesn't get us directly to the target type.
- // However, it *may* get us part of the way. Each of these
- // represents a coercion from the source type to an intermediate type.
- // Now we're going to look for conversions from the intermediate type
- // to some other type.
-
- queueIntermediates(sourceType, targetType, tuple, consideredTuples, queue);
- }
-
- // Not found anywhere. Identify the source and target type and a (sorted) list of
- // all the known coercions.
-
- throw new UnknownValueException(String.format("Could not find a coercion from type %s to type %s.",
- sourceType.getName(), targetType.getName()), buildCoercionCatalog());
- }
-
- /**
- * Coercion from null is special; we match based on the target type and its not a spanning
- * search. In many cases, we
- * return a pass-thru that leaves the value as null.
- *
- * @param targetType
- * desired type
- * @return the coercion
- */
- private Coercion searchForNullCoercion(Class targetType)
- {
- List<CoercionTuple> tuples = getTuples(Void.class, targetType);
-
- for (CoercionTuple tuple : tuples)
- {
- Class tupleTargetType = tuple.getTargetType();
-
- if (targetType.equals(tupleTargetType))
- return tuple.getCoercion();
- }
-
- // Typical case: no match, this coercion passes the null through
- // as null.
-
- return COERCION_NULL_TO_OBJECT;
- }
-
- /**
- * Builds a string listing all the coercions configured for the type coercer, sorted
- * alphabetically.
- */
- @SuppressWarnings("unchecked")
- private AvailableValues buildCoercionCatalog()
- {
- List<CoercionTuple> masterList = CollectionFactory.newList();
-
- for (List<CoercionTuple> list : sourceTypeToTuple.values())
- {
- masterList.addAll(list);
- }
-
- return new AvailableValues("Configured coercions", masterList);
- }
-
- /**
- * Seeds the pool with the initial set of coercions for the given type.
- */
- private void seedQueue(Class sourceType, Class targetType, Set<CoercionTuple> consideredTuples,
- LinkedList<CoercionTuple> queue)
- {
- // Work from the source type up looking for tuples
-
- for (Class c : new InheritanceSearch(sourceType))
- {
- List<CoercionTuple> tuples = getTuples(c, targetType);
-
- if (tuples == null)
- {
- continue;
- }
-
- for (CoercionTuple tuple : tuples)
- {
- queue.addLast(tuple);
- consideredTuples.add(tuple);
- }
-
- // Don't pull in Object -> type coercions when doing
- // a search from null.
-
- if (sourceType == Void.class)
- {
- return;
- }
- }
- }
-
- /**
- * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
- * compound coercion tuples
- * to the end of the queue.
- *
- * @param sourceType
- * the source type of the coercion
- * @param targetType
- * TODO
- * @param intermediateTuple
- * a tuple that converts from the source type to some intermediate type (that is not
- * assignable to the target type)
- * @param consideredTuples
- * set of tuples that have already been added to the pool (directly, or as a compound
- * coercion)
- * @param queue
- * the work queue of tuples
- */
- @SuppressWarnings("unchecked")
- private void queueIntermediates(Class sourceType, Class targetType, CoercionTuple intermediateTuple,
- Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
- {
- Class intermediateType = intermediateTuple.getTargetType();
-
- for (Class c : new InheritanceSearch(intermediateType))
- {
- for (CoercionTuple tuple : getTuples(c, targetType))
- {
- if (consideredTuples.contains(tuple))
- {
- continue;
- }
-
- Class newIntermediateType = tuple.getTargetType();
-
- // If this tuple is for coercing from an intermediate type back towards our
- // initial source type, then ignore it. This should only be an optimization,
- // as branches that loop back towards the source type will
- // eventually be considered and discarded.
-
- if (sourceType.isAssignableFrom(newIntermediateType))
- {
- continue;
- }
-
- // The intermediateTuple coercer gets from S --> I1 (an intermediate type).
- // The current tuple's coercer gets us from I2 --> X. where I2 is assignable
- // from I1 (i.e., I2 is a superclass/superinterface of I1) and X is a new
- // intermediate type, hopefully closer to our eventual target type.
-
- Coercion compoundCoercer = new CompoundCoercion(intermediateTuple.getCoercion(), tuple.getCoercion());
-
- CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType, compoundCoercer, false);
-
- // So, every tuple that is added to the queue can take as input the sourceType.
- // The target type may be another intermediate type, or may be something
- // assignable to the target type, which will bring the search to a successful
- // conclusion.
-
- queue.addLast(compoundTuple);
- consideredTuples.add(tuple);
- }
- }
- }
-
- /**
- * Returns a non-null list of the tuples from the source type.
- *
- * @param sourceType
- * used to locate tuples
- * @param targetType
- * used to add synthetic tuples
- * @return non-null list of tuples
- */
- private List<CoercionTuple> getTuples(Class sourceType, Class targetType)
- {
- List<CoercionTuple> tuples = sourceTypeToTuple.get(sourceType);
-
- if (tuples == null)
- {
- tuples = Collections.emptyList();
- }
-
- // So, when we see String and an Enum type, we add an additional synthetic tuple to the end
- // of the real list. This is the easiest way to accomplish this is a thread-safe and class-reloading
- // safe way (i.e., what if the Enum is defined by a class loader that gets discarded? Don't want to cause
- // memory leaks by retaining an instance). In any case, there are edge cases where we may create
- // the tuple unnecessarily (such as when an explicit string-to-enum coercion is part of the TypeCoercer
- // configuration), but on the whole, this is cheap and works.
-
- if (sourceType == String.class && Enum.class.isAssignableFrom(targetType))
- {
- tuples = extend(tuples, new CoercionTuple(sourceType, targetType, new StringToEnumCoercion(targetType)));
- }
-
- return tuples;
- }
-
- private static <T> List<T> extend(List<T> list, T extraValue)
- {
- return F.flow(list).append(extraValue).toList();
- }
-}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/eb7ec86e/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
deleted file mode 100644
index f1830a7..0000000
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InheritanceSearch.java
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2006 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.ioc.internal.util;
-
-import org.apache.tapestry5.plastic.PlasticUtils;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Set;
-
-/**
- * Used to search from a particular class up the inheritance hierarchy of extended classes and implemented interfaces.
- * <p/>
- * The search starts with the initial class (provided in the constructor). It progresses up the inheritance chain, but
- * skips java.lang.Object.
- * <p/>
- * Once classes are exhausted, the inheritance hierarchy is searched. This is a breadth-first search, rooted in the
- * interfaces implemented by the initial class at its super classes.
- * <p/>
- * Once all interfaces are exhausted, java.lang.Object is returned (it is always returned last).
- * <p/>
- * Two minor tweak to normal inheritance rules: <ul> <li> Normally, the parent class of an <em>object</em> array is
- * java.lang.Object, which is odd because FooService[] is assignable to Object[]. Thus, we tweak the search so that the
- * effective super class of FooService[] is Object[]. <li> The "super class" of a primtive type is its <em>wrapper type</em>,
- * with the exception of void, whose "super class" is left at its normal value (Object.class) </ul>
- * <p/>
- * This class implements the {@link Iterable} interface, so it can be used directly in a for loop: <code> for (Class
- * search : new InheritanceSearch(startClass)) { ... } </code>
- * <p/>
- * This class is not thread-safe.
- */
-public class InheritanceSearch implements Iterator<Class>, Iterable<Class>
-{
- private Class searchClass;
-
- private final Set<Class> addedInterfaces = CollectionFactory.newSet();
-
- private final LinkedList<Class> interfaceQueue = CollectionFactory.newLinkedList();
-
- private enum State
- {
- CLASS, INTERFACE, DONE
- }
-
- private State state;
-
- public InheritanceSearch(Class searchClass)
- {
- this.searchClass = searchClass;
-
- queueInterfaces(searchClass);
-
- state = searchClass == Object.class ? State.INTERFACE : State.CLASS;
- }
-
- private void queueInterfaces(Class searchClass)
- {
- for (Class intf : searchClass.getInterfaces())
- {
- if (addedInterfaces.contains(intf)) continue;
-
- interfaceQueue.addLast(intf);
- addedInterfaces.add(intf);
- }
- }
-
- @Override
- public Iterator<Class> iterator()
- {
- return this;
- }
-
- @Override
- public boolean hasNext()
- {
- return state != State.DONE;
- }
-
- @Override
- public Class next()
- {
- switch (state)
- {
- case CLASS:
-
- Class result = searchClass;
-
- searchClass = parentOf(searchClass);
-
- if (searchClass == null) state = State.INTERFACE;
- else queueInterfaces(searchClass);
-
- return result;
-
- case INTERFACE:
-
- if (interfaceQueue.isEmpty())
- {
- state = State.DONE;
- return Object.class;
- }
-
- Class intf = interfaceQueue.removeFirst();
-
- queueInterfaces(intf);
-
- return intf;
-
- default:
- throw new IllegalStateException();
- }
-
- }
-
- /**
- * Returns the parent of the given class. Tweaks inheritance for object arrays. Returns null instead of
- * Object.class.
- */
- private Class parentOf(Class clazz)
- {
- if (clazz != void.class && clazz.isPrimitive()) return PlasticUtils.toWrapperType(clazz);
-
- if (clazz.isArray() && clazz != Object[].class)
- {
- Class componentType = clazz.getComponentType();
-
- while (componentType.isArray()) componentType = componentType.getComponentType();
-
- if (!componentType.isPrimitive()) return Object[].class;
- }
-
- Class parent = clazz.getSuperclass();
-
- return parent != Object.class ? parent : null;
- }
-
- /**
- * @throws UnsupportedOperationException
- * always
- */
- @Override
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
-
-}