[Arakhnę-Dev] [388] * Add the new modules: math, util, attrs, ui, ui-awt, ui-base, ui-swing, ui-vector, ui-vector-awt, ui-vector-android.

[ Thread Index | Date Index | More arakhne.org/dev Archives ]


Revision: 388
Author:   galland
Date:     2013-03-20 15:54:50 +0100 (Wed, 20 Mar 2013)
Log Message:
-----------
* Add the new modules: math, util, attrs, ui, ui-awt, ui-base, ui-swing, ui-vector, ui-vector-awt, ui-vector-android.

Modified Paths:
--------------
    trunk/arakhneVmutils/arakhneVmutils-java/src/main/java/org/arakhne/vmutil/URLHandlerUtil.java
    trunk/arakhneVmutils/arakhneVmutils-java/src/main/java/org/arakhne/vmutil/file/HandlerFactory.java
    trunk/pom.xml

Added Paths:
-----------
    trunk/attrs/
    trunk/attrs/pom.xml
    trunk/attrs/src/
    trunk/attrs/src/main/
    trunk/attrs/src/main/java/
    trunk/attrs/src/main/java/org/
    trunk/attrs/src/main/java/org/arakhne/
    trunk/attrs/src/main/java/org/arakhne/afc/
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/Attribute.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeComparator.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeConstants.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeError.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeException.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeImpl.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeNameComparator.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeNotInitializedException.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeType.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValue.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValueComparator.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValueImpl.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/InvalidAttributeTypeException.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/NullAttribute.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/Timestamp.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractAttributeCollection.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractAttributeProvider.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractBufferedAttributeProvider.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeChangeEvent.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeChangeListener.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeCollection.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeIterator.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeNameStringComparator.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeProvider.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/BufferedAttributeCollection.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/HeapAttributeCollection.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/MultiAttributeCollection.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/MultiAttributeProvider.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/NoAttributeFoundException.java
    trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/ROMBasedAttributeCollection.java
    trunk/attrs/src/main/resources/
    trunk/attrs/src/main/resources/org/
    trunk/attrs/src/main/resources/org/arakhne/
    trunk/attrs/src/main/resources/org/arakhne/afc/
    trunk/attrs/src/main/resources/org/arakhne/afc/attrs/
    trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types.properties
    trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types_es.properties
    trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types_fr.properties
    trunk/attrs/src/test/
    trunk/attrs/src/test/java/
    trunk/attrs/src/test/java/org/
    trunk/attrs/src/test/java/org/arakhne/
    trunk/attrs/src/test/java/org/arakhne/afc/
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/AbstractAttrTestCase.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeComparatorTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeTypeTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeValueComparatorTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeValueTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractAttributeCollectionTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractAttributeProviderTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractBufferedAttributeProviderTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/BufferedAttributeCollectionTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/HeapAttributeCollectionTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/MultiAttributeCollectionTest.java
    trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/MultiAttributeProviderTest.java
    trunk/math/
    trunk/math/pom.xml
    trunk/math/src/
    trunk/math/src/javadoc/
    trunk/math/src/javadoc/org/
    trunk/math/src/javadoc/org/arakhne/
    trunk/math/src/javadoc/org/arakhne/math/
    trunk/math/src/javadoc/org/arakhne/math/discrete/
    trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/
    trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/
    trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_circle.png
    trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_point.png
    trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_rect.png
    trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_segment.png
    trunk/math/src/javadoc/org/arakhne/math/generic/
    trunk/math/src/javadoc/org/arakhne/math/generic/doc-files/
    trunk/math/src/javadoc/org/arakhne/math/generic/doc-files/fillrule-evenodd.png
    trunk/math/src/javadoc/org/arakhne/math/generic/doc-files/fillrule-nonzero.png
    trunk/math/src/main/
    trunk/math/src/main/java/
    trunk/math/src/main/java/org/
    trunk/math/src/main/java/org/arakhne/
    trunk/math/src/main/java/org/arakhne/afc/
    trunk/math/src/main/java/org/arakhne/afc/math/
    trunk/math/src/main/java/org/arakhne/afc/math/MathConstants.java
    trunk/math/src/main/java/org/arakhne/afc/math/MathUtil.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/AbstractRectangularShape2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/AbstractShape2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Circle2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Ellipse2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Path2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathElement2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathElementType.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathIterator2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathWindingRule.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Point2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Rectangle2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/RoundRectangle2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Segment2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Shape2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Tuple2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Tuple2fComparator.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/UnmodifiablePoint2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Vector2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object3d/
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object3d/Point3f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object3d/Quaternion.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object3d/Tuple3f.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object3d/Tuple3fComparator.java
    trunk/math/src/main/java/org/arakhne/afc/math/continous/object3d/Vector3f.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/AbstractRectangularShape2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/AbstractShape2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Circle2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Path2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/PathElement2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/PathIterator2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Point2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Rectangle2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Segment2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Shape2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Tuple2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Tuple2iComparator.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object2d/Vector2i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object3d/
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object3d/Point3i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object3d/Tuple3i.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object3d/Tuple3iComparator.java
    trunk/math/src/main/java/org/arakhne/afc/math/discrete/object3d/Vector3i.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/
    trunk/math/src/main/java/org/arakhne/afc/math/generic/PathElementType.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/PathWindingRule.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/Point2D.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/Point3D.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/Shape2D.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/Tuple2D.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/Tuple3D.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/Vector2D.java
    trunk/math/src/main/java/org/arakhne/afc/math/generic/Vector3D.java
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/Matrix2f.java
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/Matrix3f.java
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/Matrix4f.java
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/SingularMatrixException.java
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform2D.java
    trunk/math/src/main/java/org/arakhne/afc/math/matrix/Transform3D.java
    trunk/math/src/main/resources/
    trunk/math/src/main/resources/org/
    trunk/math/src/main/resources/org/arakhne/
    trunk/math/src/main/resources/org/arakhne/afc/
    trunk/math/src/main/resources/org/arakhne/afc/math/
    trunk/math/src/main/resources/org/arakhne/afc/math/continuous/
    trunk/math/src/main/resources/org/arakhne/afc/math/continuous/Matrix3f.properties
    trunk/math/src/main/resources/org/arakhne/afc/math/continuous/Matrix3f_fr.properties
    trunk/math/src/test/
    trunk/math/src/test/java/
    trunk/math/src/test/java/org/
    trunk/math/src/test/java/org/arakhne/
    trunk/math/src/test/java/org/arakhne/afc/
    trunk/math/src/test/java/org/arakhne/afc/math/
    trunk/math/src/test/java/org/arakhne/afc/math/AbstractMathTestCase.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/
    trunk/math/src/test/java/org/arakhne/afc/math/continous/matrix/
    trunk/math/src/test/java/org/arakhne/afc/math/continous/matrix/Matrix2fTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/matrix/Transform2DTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/AbstractRectangularShape2fTestCase.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/AbstractShape2fTestCase.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Circle2fTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Ellipse2fTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Path2fPointCollectionTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Path2fTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Rectangle2fTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/RoundRectangle2fTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/continous/object2d/Segment2fTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/discrete/
    trunk/math/src/test/java/org/arakhne/afc/math/discrete/object2d/
    trunk/math/src/test/java/org/arakhne/afc/math/discrete/object2d/AbstractRectangularShape2iTestCase.java
    trunk/math/src/test/java/org/arakhne/afc/math/discrete/object2d/AbstractShape2iTestCase.java
    trunk/math/src/test/java/org/arakhne/afc/math/discrete/object2d/Circle2iTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/discrete/object2d/Path2iTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/discrete/object2d/Rectangle2iTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/discrete/object2d/Segment2iTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/matrix/
    trunk/math/src/test/java/org/arakhne/afc/math/matrix/Matrix2fTest.java
    trunk/math/src/test/java/org/arakhne/afc/math/matrix/Transform2DTest.java
    trunk/math/src/test/resources/
    trunk/math/src/test/resources/org/
    trunk/math/src/test/resources/org/arakhne/
    trunk/math/src/test/resources/org/arakhne/afc/
    trunk/math/src/test/resources/org/arakhne/afc/math/
    trunk/math/src/test/resources/org/arakhne/afc/math/discrete/
    trunk/math/src/test/resources/org/arakhne/afc/math/discrete/object2d/
    trunk/math/src/test/resources/org/arakhne/afc/math/discrete/object2d/Segment2i.ods
    trunk/ui/
    trunk/ui/pom.xml
    trunk/ui/ui-awt/
    trunk/ui/ui-awt/pom.xml
    trunk/ui/ui-awt/src/
    trunk/ui/ui-awt/src/main/
    trunk/ui/ui-awt/src/main/java/
    trunk/ui/ui-awt/src/main/java/org/
    trunk/ui/ui-awt/src/main/java/org/arakhne/
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/AbstractLODGraphics2D.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/AwtUtil.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/DefaultLODGraphics2D.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/DoubleDimension.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/ExceptionListener.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/FloatDimension.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/FontComparator.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/LODGraphics2D.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/SupportedShape.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/UnsupportedShapeException.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/VirtualScreenGraphics2D.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/VirtualizableShape.java
    trunk/ui/ui-awt/src/main/java/org/arakhne/afc/ui/awt/ZoomableContextUtil.java
    trunk/ui/ui-awt/src/main/resources/
    trunk/ui/ui-awt/src/test/
    trunk/ui/ui-awt/src/test/java/
    trunk/ui/ui-awt/src/test/resources/
    trunk/ui/ui-base/
    trunk/ui/ui-base/pom.xml
    trunk/ui/ui-base/src/
    trunk/ui/ui-base/src/main/
    trunk/ui/ui-base/src/main/java/
    trunk/ui/ui-base/src/main/java/org/
    trunk/ui/ui-base/src/main/java/org/arakhne/
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/Graphics2DLOD.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/MouseCursor.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/StringAnchor.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/TextAlignment.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/ZoomableContext.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionMode.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeAdapter.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeException.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeListener.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeManager.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/ActionModeManagerOwner.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/SelectableInteractionAdapter.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/SelectableInteractionEvent.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/actionmode/SelectableInteractionListener.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/InputEvent.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/KeyEvent.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/event/PointerEvent.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/selection/
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/selection/Selectable.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/selection/SelectionEvent.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/selection/SelectionListener.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/selection/SelectionManager.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/selection/TreeSetSelectionManager.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/AbstractUndoable.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/DefaultUndoManager.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/UndoListener.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/UndoManager.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/Undoable.java
    trunk/ui/ui-base/src/main/java/org/arakhne/afc/ui/undo/UndoableGroup.java
    trunk/ui/ui-base/src/main/resources/
    trunk/ui/ui-base/src/main/resources/org/
    trunk/ui/ui-base/src/main/resources/org/arakhne/
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/actionmode/
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/actionmode/ActionMode.properties
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/actionmode/ActionModeManager.properties
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/actionmode/ActionModeManager_fr.properties
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/actionmode/ActionMode_fr.properties
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/undo/
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/undo/DefaultUndoManager.properties
    trunk/ui/ui-base/src/main/resources/org/arakhne/afc/ui/undo/DefaultUndoManager_fr.properties
    trunk/ui/ui-base/src/test/
    trunk/ui/ui-base/src/test/java/
    trunk/ui/ui-base/src/test/resources/
    trunk/ui/ui-swing/
    trunk/ui/ui-swing/pom.xml
    trunk/ui/ui-swing/src/
    trunk/ui/ui-swing/src/main/
    trunk/ui/ui-swing/src/main/java/
    trunk/ui/ui-swing/src/main/java/org/
    trunk/ui/ui-swing/src/main/java/org/arakhne/
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/FileFilterSwing.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/JColorSelector.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/JGroupButton.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/JPopupTextField.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/StandardAction.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/event/
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/event/KeyEventSwing.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/event/PointerEventSwing.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/progress/
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/progress/ProgressBarModel.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/progress/ProgressMonitor.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/progress/ProgressionProgressBarWrapper.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/undo/
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/undo/AbstractCallableUndoableEdit.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/undo/UndoManagerSwing.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/undo/UndoableAction.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/undo/UndoableGroupSwing.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/InternalZoomablePanel.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ScrollingMethod.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomableGraphics2D.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomablePanel.java
    trunk/ui/ui-swing/src/main/java/org/arakhne/afc/ui/swing/zoompanel/ZoomableViewport.java
    trunk/ui/ui-swing/src/main/resources/
    trunk/ui/ui-swing/src/test/
    trunk/ui/ui-swing/src/test/java/
    trunk/ui/ui-swing/src/test/resources/
    trunk/ui/ui-vector/
    trunk/ui/ui-vector/pom.xml
    trunk/ui/ui-vector/src/
    trunk/ui/ui-vector/src/main/
    trunk/ui/ui-vector/src/main/java/
    trunk/ui/ui-vector/src/main/java/org/
    trunk/ui/ui-vector/src/main/java/org/arakhne/
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/AbstractVectorGraphics2D.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Color.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Composite.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Dimension.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Font.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/FontComparator.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/FontMetrics.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/FontStyle.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Image.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/ImageObserver.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Margins.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Paint.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/PathUtil.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Pdf.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Raster.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/Stroke.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/VectorGraphics2D.java
    trunk/ui/ui-vector/src/main/java/org/arakhne/afc/ui/vector/VectorToolkit.java
    trunk/ui/ui-vector/src/main/resources/
    trunk/ui/ui-vector/src/main/resources/org/
    trunk/ui/ui-vector/src/main/resources/org/arakhne/
    trunk/ui/ui-vector/src/main/resources/org/arakhne/afc/
    trunk/ui/ui-vector/src/main/resources/org/arakhne/afc/ui/
    trunk/ui/ui-vector/src/main/resources/org/arakhne/afc/ui/vector/
    trunk/ui/ui-vector/src/main/resources/org/arakhne/afc/ui/vector/VectorToolkit.properties
    trunk/ui/ui-vector/src/main/resources/org/arakhne/afc/ui/vector/no_picture.png
    trunk/ui/ui-vector/src/test/
    trunk/ui/ui-vector/src/test/java/
    trunk/ui/ui-vector/src/test/resources/
    trunk/ui/ui-vector-android/
    trunk/ui/ui-vector-android/pom.xml
    trunk/ui/ui-vector-android/src/
    trunk/ui/ui-vector-android/src/main/
    trunk/ui/ui-vector-android/src/main/java/
    trunk/ui/ui-vector-android/src/main/java/org/
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidColor.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidComposite.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidDimension.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidImage.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidMargins.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidPaint.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidPdf.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidRaster.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/AndroidVectorToolkit.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/DelegatedVectorGraphics2D.java
    trunk/ui/ui-vector-android/src/main/java/org/arakhne/afc/ui/vector/android/NativeWrapper.java
    trunk/ui/ui-vector-android/src/main/javadoc/
    trunk/ui/ui-vector-android/src/main/resources/
    trunk/ui/ui-vector-android/src/test/
    trunk/ui/ui-vector-android/src/test/java/
    trunk/ui/ui-vector-android/src/test/resources/
    trunk/ui/ui-vector-awt/
    trunk/ui/ui-vector-awt/pom.xml
    trunk/ui/ui-vector-awt/src/
    trunk/ui/ui-vector-awt/src/main/
    trunk/ui/ui-vector-awt/src/main/java/
    trunk/ui/ui-vector-awt/src/main/java/org/
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtBufferedImage.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtColor.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtComposite.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtDimension.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtFont.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtFontMetrics.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtImage.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtImageObserver.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtMargins.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtPaint.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtPath.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtPathIterator.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtPdf.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtRaster.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtStroke.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/AwtVectorToolkit.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/DelegatedVectorGraphics2D.java
    trunk/ui/ui-vector-awt/src/main/java/org/arakhne/afc/ui/vector/awt/NativeWrapper.java
    trunk/ui/ui-vector-awt/src/main/resources/
    trunk/ui/ui-vector-awt/src/test/
    trunk/ui/ui-vector-awt/src/test/java/
    trunk/ui/ui-vector-awt/src/test/resources/
    trunk/util/
    trunk/util/pom.xml
    trunk/util/src/
    trunk/util/src/main/
    trunk/util/src/main/java/
    trunk/util/src/main/java/org/
    trunk/util/src/main/java/org/arakhne/
    trunk/util/src/main/java/org/arakhne/afc/
    trunk/util/src/main/java/org/arakhne/afc/io/
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/AbstractFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/BMPFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/DOTFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/EPSFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/FileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/GIFFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/GMLFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/GXLFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/GraphMLFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/ImageFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/JPEGFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/JavaFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/MultiFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/NGRFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/PDFFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/PNGFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/SVGFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/filefilter/XMLFileFilter.java
    trunk/util/src/main/java/org/arakhne/afc/io/stream/
    trunk/util/src/main/java/org/arakhne/afc/io/stream/ReaderInputStream.java
    trunk/util/src/main/java/org/arakhne/afc/io/stream/UnclosableInputStream.java
    trunk/util/src/main/java/org/arakhne/afc/io/stream/UnclosableOutputStream.java
    trunk/util/src/main/java/org/arakhne/afc/io/stream/WriterOutputStream.java
    trunk/util/src/main/java/org/arakhne/afc/progress/
    trunk/util/src/main/java/org/arakhne/afc/progress/DefaultProgression.java
    trunk/util/src/main/java/org/arakhne/afc/progress/Progression.java
    trunk/util/src/main/java/org/arakhne/afc/progress/ProgressionAdapter.java
    trunk/util/src/main/java/org/arakhne/afc/progress/ProgressionConsoleMonitor.java
    trunk/util/src/main/java/org/arakhne/afc/progress/ProgressionEvent.java
    trunk/util/src/main/java/org/arakhne/afc/progress/ProgressionInputStream.java
    trunk/util/src/main/java/org/arakhne/afc/progress/ProgressionListener.java
    trunk/util/src/main/java/org/arakhne/afc/progress/ProgressionOuputStream.java
    trunk/util/src/main/java/org/arakhne/afc/progress/ProgressionUtil.java
    trunk/util/src/main/java/org/arakhne/afc/progress/SubProgressionModel.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/EmptyIterator.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/ModifiableCollectionSizedIterator.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/ModifiableCollectionSizedIteratorOwner.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/MultiSizedIterator.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/SizedIterator.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/UnmodifiableCollectionSizedIterator.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/UnmodifiableMapKeySizedIterator.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/UnmodifiableMapValueSizedIterator.java
    trunk/util/src/main/java/org/arakhne/afc/sizediterator/UnmodifiableSizedIterator.java
    trunk/util/src/main/java/org/arakhne/afc/text/
    trunk/util/src/main/java/org/arakhne/afc/text/TextUtil.java
    trunk/util/src/main/java/org/arakhne/afc/util/
    trunk/util/src/main/java/org/arakhne/afc/util/HashCodeUtil.java
    trunk/util/src/main/java/org/arakhne/afc/util/ListUtil.java
    trunk/util/src/main/java/org/arakhne/afc/util/ListenerCollection.java
    trunk/util/src/main/java/org/arakhne/afc/util/MultiValue.java
    trunk/util/src/main/java/org/arakhne/afc/util/Pair.java
    trunk/util/src/main/java/org/arakhne/afc/util/PropertyOwner.java
    trunk/util/src/main/java/org/arakhne/afc/util/UnmodifiableIterator.java
    trunk/util/src/main/resources/
    trunk/util/src/main/resources/org/
    trunk/util/src/main/resources/org/arakhne/
    trunk/util/src/main/resources/org/arakhne/afc/
    trunk/util/src/main/resources/org/arakhne/afc/io/
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/BMPFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/BMPFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/DOTFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/DOTFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/EPSFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/EPSFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/GIFFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/GIFFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/GMLFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/GMLFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/GXLFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/GXLFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/GraphMLFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/GraphMLFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/ImageFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/ImageFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/JPEGFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/JPEGFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/JavaFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/JavaFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/NGRFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/NGRFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/PDFFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/PDFFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/PNGFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/PNGFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/SVGFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/SVGFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/XMLFileFilter.properties
    trunk/util/src/main/resources/org/arakhne/afc/io/filefilter/XMLFileFilter_fr.properties
    trunk/util/src/main/resources/org/arakhne/afc/util/
    trunk/util/src/main/resources/org/arakhne/afc/util/MultiValue.properties
    trunk/util/src/main/resources/org/arakhne/afc/util/MultiValue_fr.properties
    trunk/util/src/test/
    trunk/util/src/test/java/
    trunk/util/src/test/resources/

Modified: trunk/arakhneVmutils/arakhneVmutils-java/src/main/java/org/arakhne/vmutil/URLHandlerUtil.java
===================================================================
--- trunk/arakhneVmutils/arakhneVmutils-java/src/main/java/org/arakhne/vmutil/URLHandlerUtil.java	2013-01-14 15:11:56 UTC (rev 387)
+++ trunk/arakhneVmutils/arakhneVmutils-java/src/main/java/org/arakhne/vmutil/URLHandlerUtil.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -2,7 +2,7 @@
  * $Id$
  * 
  * Copyright (C) 2004-2009 Stephane GALLAND.
- * Copyright (C) 2012 Stephane GALLAND.
+ * Copyright (C) 2012-13 Stephane GALLAND.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,9 +22,12 @@
 
 package org.arakhne.vmutil;
 
+import java.net.URLStreamHandler;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 /** Utilities around URLHandler.
  * 
@@ -38,6 +41,16 @@
 
 	private static final String HANDLER_PACKAGES = "java.protocol.handler.pkgs"; //$NON-NLS-1$
 	
+	/** Replies an iterator on the handlers that are supporting the given protocol.
+	 * 
+	 * @param protocol
+	 * @return the iterator.
+	 * @since 7.2
+	 */
+	public static Iterator<Class<? extends URLStreamHandler>> getHandlersFor(String protocol) {
+		return new HandlerIterator(protocol);
+	}
+	
 	private static void install(String... packageNames) {
 		List<String> array = new LinkedList<String>();
 
@@ -116,5 +129,73 @@
 		uninstall(URLHandlerUtil.class.getPackage().getName());
 	}
 
+	/**
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 * @since 7.2
+	 */
+	private static class HandlerIterator implements Iterator<Class<? extends URLStreamHandler>> {
+
+		private final String protocol;
+		private final String[] packages;
+		private int position = 0;
+		
+		private Class<? extends URLStreamHandler> next;
+		
+		/**
+		 * @param protocol
+		 */
+		public HandlerIterator(String protocol) {
+			this.protocol = protocol;
+			String str = System.getProperty(HANDLER_PACKAGES);
+			if (str==null)
+				this.packages = new String[0];
+			else
+				this.packages = str.split("\\|"); //$NON-NLS-1$
+			
+			searchNext();
+		}
+		
+		@SuppressWarnings("unchecked")
+		private void searchNext() {
+			this.next = null;
+			ClassLoader clsLoader = getClass().getClassLoader();
+			while (this.next==null && this.position<this.packages.length) {
+				String typename = this.packages[this.position++];
+
+				try {
+					Class<?> type = clsLoader.loadClass(typename+"."+this.protocol+".Handler"); //$NON-NLS-1$ //$NON-NLS-2$
+					if (type!=null && URLStreamHandler.class.isAssignableFrom(type)) {
+						this.next = (Class<? extends URLStreamHandler>)type;
+					}
+				}
+				catch(Throwable _) {
+					//
+				}
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.next!=null;
+		}
+
+		@Override
+		public Class<? extends URLStreamHandler> next() {
+			Class<? extends URLStreamHandler> n = this.next;
+			if (n==null) throw new NoSuchElementException();
+			searchNext();
+			return n;
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+		
+	}
+	
 }
 

Modified: trunk/arakhneVmutils/arakhneVmutils-java/src/main/java/org/arakhne/vmutil/file/HandlerFactory.java
===================================================================
--- trunk/arakhneVmutils/arakhneVmutils-java/src/main/java/org/arakhne/vmutil/file/HandlerFactory.java	2013-01-14 15:11:56 UTC (rev 387)
+++ trunk/arakhneVmutils/arakhneVmutils-java/src/main/java/org/arakhne/vmutil/file/HandlerFactory.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -1,7 +1,7 @@
 /* 
  * $Id$
  * 
- * Copyright (C) 2010 Stephane GALLAND.
+ * Copyright (C) 2010-13 Stephane GALLAND.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public


Property changes on: trunk/attrs
___________________________________________________________________
Added: svn:ignore
   + .classpath
..metadata
..settings
..project
target
bin


Added: trunk/attrs/pom.xml
===================================================================
--- trunk/attrs/pom.xml	                        (rev 0)
+++ trunk/attrs/pom.xml	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,46 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<artifactId>afc</artifactId>
+		<groupId>org.arakhne.afc</groupId>
+		<version>4.5-SNAPSHOT</version>
+	</parent>
+
+	<groupId>org.arakhne.afc</groupId>
+	<artifactId>attrs</artifactId>
+	<version>1.0-SNAPSHOT</version>
+	<name>Arakhne Attribute API</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.arakhne.afc</groupId>
+			<artifactId>arakhneVmutils</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.arakhne.afc</groupId>
+			<artifactId>arakhneRefs</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.arakhne.afc</groupId>
+			<artifactId>math</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.arakhne.afc.ui</groupId>
+			<artifactId>ui-vector</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+			<optional>true</optional>
+		</dependency>
+		<dependency>
+			<groupId>org.arakhne.afc.ui</groupId>
+			<artifactId>ui-vector-awt</artifactId>
+			<scope>test</scope>
+			<optional>true</optional>
+		</dependency>
+	</dependencies>
+
+</project>

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/Attribute.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/Attribute.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/Attribute.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,79 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.util.Comparator;
+
+
+/**
+ * This interface contains a metadata with a name.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface Attribute extends AttributeValue, AttributeConstants {
+
+	/**
+	 * Replies a comparator suitable for attribute based on the names
+	 * of the attributes only.
+	 * 
+	 * @return a comparator, never <code>null</code>
+	 * @see #valueComparator()
+	 * @see #comparator()
+	 */
+	public Comparator<? extends Attribute> nameComparator();
+
+	/**
+	 * Replies a comparator suitable for attribute based on the names
+	 * of the attributes only.
+	 * 
+	 * @return a comparator, never <code>null</code>
+	 * @see #nameComparator()
+	 * @see #valueComparator()
+	 */
+	public Comparator<? extends Attribute> comparator();
+
+	/** The this value with the content of the specified one.
+	 * 
+	 * @param value
+	 * @throws InvalidAttributeTypeException
+	 */
+	public void setAttribute(Attribute value) throws InvalidAttributeTypeException;
+
+	/**
+	 * Replies the name of the metadata.
+	 * 
+	 * @return the name of the attribute.
+	 */
+	public String getName() ;
+
+	/**
+	 * Set the name of this metadata.
+	 * 
+	 * @param name
+	 */
+	public void setName(String name) ;
+	
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeComparator.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeComparator.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeComparator.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,90 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.util.Comparator;
+
+
+
+/**
+ * This class permits to compare to {@link Attribute}.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeComparator implements Comparator<Attribute> {
+	
+    /**
+     * Compares its two arguments for order.  Returns a negative integer,
+     * zero, or a positive integer as the first argument is less than, equal
+     * to, or greater than the second.<p>
+     *
+     * In the foregoing description, the notation
+     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
+     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
+     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
+     * <i>expression</i> is negative, zero or positive.<p>
+     *
+     * The implementor must ensure that <tt>sgn(compare(x, y)) ==
+     * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
+     * implies that <tt>compare(x, y)</tt> must throw an exception if and only
+     * if <tt>compare(y, x)</tt> throws an exception.)<p>
+     *
+     * The implementor must also ensure that the relation is transitive:
+     * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
+     * <tt>compare(x, z)&gt;0</tt>.<p>
+     *
+     * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt>
+     * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
+     * <tt>z</tt>.<p>
+     *
+     * It is generally the case, but <i>not</i> strictly required that
+     * <tt>(compare(x, y)==0) == (x.equals(y))</tt>.  Generally speaking,
+     * any comparator that violates this condition should clearly indicate
+     * this fact.  The recommended language is "Note: this comparator
+     * imposes orderings that are inconsistent with equals."
+     *
+     * @param arg0 the first object to be compared.
+     * @param arg1 the second object to be compared.
+     * @return a negative integer, zero, or a positive integer as the
+     * 	       first argument is less than, equal to, or greater than the
+     *	       second.
+     * @throws ClassCastException if the arguments' types prevent them from
+     * 	       being compared by this comparator.
+     */
+	public int compare(AttributeValue arg0, AttributeValue arg1) {
+		if ((arg0 instanceof Attribute)&&(arg1 instanceof Attribute))
+			return compare((Attribute)arg0,(Attribute)arg1);
+		return AttributeValueImpl.compareValues(arg0,arg1);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public int compare(Attribute arg0, Attribute arg1) {
+		return AttributeImpl.compareAttrs(arg0, arg1);
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeConstants.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeConstants.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeConstants.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,93 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import org.arakhne.vmutil.URISchemeType;
+
+/**
+ * This interface contains several constant names.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface AttributeConstants {
+
+	/** Default URI and URL scheme used to build URLs and URIs.
+	 */
+	public static final URISchemeType DEFAULT_SCHEME = URISchemeType.HTTP;
+
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String TRUE_CONSTANT = "true"; //$NON-NLS-1$
+	
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String YES_CONSTANT = "yes"; //$NON-NLS-1$
+
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String OUI_CONSTANT = "oui"; //$NON-NLS-1$
+
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String T_CONSTANT = "t"; //$NON-NLS-1$
+
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String O_CONSTANT = "o"; //$NON-NLS-1$
+
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String Y_CONSTANT = "y"; //$NON-NLS-1$
+
+	/** String constant for the <code>false</code> boolean constant.
+	 */
+	public static final String FALSE_CONSTANT = "false"; //$NON-NLS-1$
+	
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String NO_CONSTANT = "no"; //$NON-NLS-1$
+
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String NON_CONSTANT = "non"; //$NON-NLS-1$
+
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String F_CONSTANT = "f"; //$NON-NLS-1$
+
+	/** String constant for the <code>true</code> boolean constant.
+	 */
+	public static final String N_CONSTANT = "n"; //$NON-NLS-1$
+
+	/** Attribute "name".
+	 */
+	public static final String ATTR_NAME = "name"; //$NON-NLS-1$
+	
+	/** Attirbute "id".
+	 */
+	public static final String ATTR_IDENTIFIER = "id"; //$NON-NLS-1$
+	
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeError.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeError.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeError.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,58 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+/**
+ * This exception is generated each time something wrong append
+ * with attributes.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeError extends RuntimeException {
+	
+	private static final long serialVersionUID = 3139198792703646207L;
+
+	/**
+	 */
+	public AttributeError() {
+		//
+	}
+	
+	/**
+	 * @param name is the name of the attribute on which something wrong appended.
+	 */
+	public AttributeError(String name) {
+		super(name);
+	}
+
+	/**
+	 * @param e is the exception to forward.
+	 */
+	public AttributeError(Throwable e) {
+		super(e);
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeException.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeException.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeException.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,58 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+/**
+ * This exception is generated each time something wrong append
+ * with attributes.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeException extends Exception {
+	
+	private static final long serialVersionUID = 3139198792703646207L;
+
+	/**
+	 */
+	public AttributeException() {
+		//
+	}
+	
+	/**
+	 * @param name is the name of the attribute on which something wrong appended.
+	 */
+	public AttributeException(String name) {
+		super(name);
+	}
+
+	/**
+	 * @param e is the exception to forward.
+	 */
+	public AttributeException(Throwable e) {
+		super(e);
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeImpl.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeImpl.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeImpl.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,492 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.UUID;
+
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Point3D;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+
+/**
+ * This class contains an attribute value.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeImpl extends AttributeValueImpl implements Attribute {
+	
+	/** Compare the two specified attributes.
+	 *
+	 * @param arg0
+	 * @param arg1
+	 * @return replies a negative value if <var>arg0</var> is lesser than
+	 * <var>arg1</var>, a positive value if <var>arg0</var> is greater than
+	 * <var>arg1</var>, or <code>0</code> if they are equal.
+	 * @see AttributeComparator
+	 */
+	public static int compareAttrs(Attribute arg0, Attribute arg1) {
+		if (arg0==arg1) return 0;
+		if (arg0==null) return 1;
+		if (arg1==null) return -1;
+		
+		String n0 = arg0.getName();
+		String n1 = arg1.getName();
+		int cmp = compareAttrNames(n0, n1);
+		
+		if (cmp==0)
+			return compareValues(arg0,arg1);
+		
+		return cmp;
+	}
+	
+	/** Compare the two specified attribute names.
+	 *
+	 * @param arg0
+	 * @param arg1
+	 * @return replies a negative value if <var>arg0</var> is lesser than
+	 * <var>arg1</var>, a positive value if <var>arg0</var> is greater than
+	 * <var>arg1</var>, or <code>0</code> if they are equal.
+	 * @see AttributeNameComparator
+	 */
+	public static int compareAttrNames(String arg0, String arg1) {
+		if (arg0==arg1) return 0;
+		if (arg0==null) return Integer.MAX_VALUE;
+		if (arg1==null) return Integer.MIN_VALUE;
+		return arg0.compareToIgnoreCase(arg1);
+	}
+
+	/**
+	 * Name of the metadata.
+	 */
+	private String name = null;
+
+	/**
+	 * Uninitialized attribute.
+	 */
+	public AttributeImpl() {
+		//
+	}
+
+	/**
+	 * Uninitialized attribute.
+	 * 
+	 * @param type is the type of the attribute.
+	 */
+	public AttributeImpl(AttributeType type) {
+		super(type);
+	}
+	
+	/**
+	 * Uninitialized attribute.
+	 * 
+	 * @param name is the name of the attribute
+	 */
+	public AttributeImpl(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * Uninitialized attribute.
+	 * 
+	 * @param name is the name of the attribute
+	 * @param type is the type of the attribute.
+	 */
+	public AttributeImpl(String name, AttributeType type) {
+		super(type);
+		this.name = name;
+	}
+
+	/**
+	 * Initialized attribute with the given raw value.
+	 * The raw value must be compatible with the internal
+	 * representation of the value.
+	 * 
+	 * @param name is the name of the attribute
+	 * @param type is the type of the attribute.
+	 * @param rawValue is the rawValue.
+	 */
+	public AttributeImpl(String name, AttributeType type, Object rawValue) {
+		super(type, rawValue);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, AttributeValue value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(Attribute value) {
+		super(value);
+		this.name = value.getName();
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, boolean value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, Color value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, Date value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, float value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, double value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, Image value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, int value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, long value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, Object value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, Point2D value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param x is the value of this new attribute.
+	 * @param y is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, float x, float y) {
+		super(x,y);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param x is the value of this new attribute.
+	 * @param y is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, double x, double y) {
+		super(x,y);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the vaule of this new attribute.
+	 */
+	public AttributeImpl(String name, Point3D value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param x is the value of this new attribute.
+	 * @param y is the value of this new attribute.
+	 * @param z is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, float x, float y, float z) {
+		super(x,y,z);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param x is the value of this new attribute.
+	 * @param y is the value of this new attribute.
+	 * @param z is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, double x, double y, double z) {
+		super(x,y,z);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, String value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, Point2D[] value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, Point3D[] value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, Enum<?> value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, InetAddress value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, InetSocketAddress value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, URI value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, URL value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, UUID value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * @param name is the name of the attribute
+	 * @param value is the value of this new attribute.
+	 */
+	public AttributeImpl(String name, Class<?> value) {
+		super(value);
+		this.name = name;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @param o {@inheritDoc}
+	 * @return {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof Attribute) {
+			return compareAttrs(this, (Attribute)o)==0;
+		}
+		return super.equals(o);
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+        final int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + (this.name!=null ? this.name.hashCode() : 0);
+        result = PRIME * result + super.hashCode();
+        return result;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @return {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder str = new StringBuilder();
+		str.append('[');
+		str.append((this.name==null)
+				? "???" //$NON-NLS-1$
+				: this.name);
+		str.append('=');
+		try {
+			str.append((getValue()==null)
+					? "???" //$NON-NLS-1$
+					: getValue().toString());
+		}
+		catch (AttributeException e) {
+			str.append("???"); //$NON-NLS-1$
+		}
+		str.append(':');
+		str.append(getType().toString());
+		str.append(']');
+		return str.toString();
+	}
+	
+	/** Assert that the attribute value was assigned and not <code>null</code>.
+	 */
+	@Override
+	protected void assertAssignedAndNotNull() throws AttributeNotInitializedException {
+		try {
+			super.assertAssignedAndNotNull();
+		}
+		catch(AttributeNotInitializedException _) {
+			throw new AttributeNotInitializedException(this.name);
+		}
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public String getName() {
+		return this.name;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setAttribute(Attribute value) throws InvalidAttributeTypeException {
+		setValue(value);
+		this.name = value.getName();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Comparator<? extends Attribute> nameComparator() {
+		return new AttributeNameComparator();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Comparator<? extends Attribute> comparator() {
+		return new AttributeComparator();
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeNameComparator.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeNameComparator.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeNameComparator.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,46 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.util.Comparator;
+
+
+
+/**
+ * Comparator for attribute names.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeNameComparator implements Comparator<Attribute> {
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public int compare(Attribute arg0, Attribute arg1) {
+		return AttributeImpl.compareAttrNames(arg0.getName(), arg1.getName());
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeNotInitializedException.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeNotInitializedException.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeNotInitializedException.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,51 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+/**
+ * This exception is generated each time an uninitialized
+ * attribute value was accessed.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeNotInitializedException extends AttributeException {
+	
+	private static final long serialVersionUID = -8155807821254667201L;
+
+	/**
+	 */
+	public AttributeNotInitializedException() {
+		//
+	}
+
+	/**
+	 * @param name is the name of the uninitialized attribute.
+	 */
+	public AttributeNotInitializedException(String name) {
+		super(name);
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeType.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeType.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeType.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,719 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.lang.reflect.Array;
+import java.math.BigInteger;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.arakhne.afc.math.continous.object2d.Point2f;
+import org.arakhne.afc.math.continous.object3d.Point3f;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Point3D;
+import org.arakhne.afc.math.generic.Tuple2D;
+import org.arakhne.afc.math.generic.Tuple3D;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+import org.arakhne.afc.ui.vector.VectorToolkit;
+import org.arakhne.vmutil.locale.Locale;
+
+/**
+ * List of supported types for the metadata.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public enum AttributeType {
+
+	/** Represents an enumeration.
+	 * @see Enum
+	 */
+	ENUMERATION,
+
+	/** Represents a Java type.
+	 */
+	TYPE,
+
+	/** Represents an unique universal identifier.
+	 */
+	UUID,
+
+	/** Represents an integer.
+	 */
+	INTEGER,
+	
+	/** Represents a floating number.
+	 */
+	REAL,
+	
+	/** Represents a date.
+	 */
+	DATE,
+	
+	/** Represents a boolean value.
+	 */
+	BOOLEAN,
+	
+	/** Represents an Internet address.
+	 * @see Inet4Address
+	 * @see Inet6Address
+	 * @see InetSocketAddress
+	 */
+	INET_ADDRESS,
+
+	/** Represents a color value.
+	 */
+	COLOR,
+
+	/** Represents an URL.
+	 * @see java.net.URL
+	 */
+	URL,
+
+	/** Represents an URI.
+	 * @see java.net.URI
+	 */
+	URI,
+
+	/** Represents a timestamp value.
+	 */
+	TIMESTAMP,
+
+	/** Represents a 3d point value.
+	 */
+	POINT3D,
+
+	/** Represents a 2d point value.
+	 */
+	POINT,
+
+	/** Represents a list of 3d points.
+	 */
+	POLYLINE3D,
+
+	/** Represents a list of 2d points.
+	 */
+	POLYLINE,
+
+	/** Represents an image value.
+	 */
+	IMAGE,
+		
+	/** Represents a string.
+	 */
+	STRING,
+	
+	/** Represents a java-object value.
+	 */
+	OBJECT;	
+	
+	private static final String NAME_RESOURCE_FILE;
+	
+	static {
+		String pName = AttributeType.class.getPackage().getName();
+		NAME_RESOURCE_FILE = pName+".types"; //$NON-NLS-1$
+	}
+	
+	/** Replies the name of this type (localized).
+	 * 
+	 * @return the localized name of this type.
+	 */
+	public String getName() {
+		switch(this) {
+		case INTEGER:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"INTEGER"); //$NON-NLS-1$ 
+		case REAL:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"FLOAT"); //$NON-NLS-1$ 
+		case STRING:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"STRING"); //$NON-NLS-1$ 
+		case BOOLEAN:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"BOOLEAN"); //$NON-NLS-1$ 
+		case DATE:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"DATE"); //$NON-NLS-1$ 
+		case TIMESTAMP:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"TIMESTAMP"); //$NON-NLS-1$ 
+		case OBJECT:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"OBJECT"); //$NON-NLS-1$ 
+		case POINT3D:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"POINT3D"); //$NON-NLS-1$ 
+		case POINT:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"POINT2D"); //$NON-NLS-1$ 
+		case COLOR:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"COLOR"); //$NON-NLS-1$ 
+		case IMAGE:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"ICON"); //$NON-NLS-1$ 
+		case POLYLINE:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"POLYLINE"); //$NON-NLS-1$ 
+		case POLYLINE3D:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"POLYLINE3D"); //$NON-NLS-1$ 
+		case UUID:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"UUID"); //$NON-NLS-1$ 
+		case URL:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"URL"); //$NON-NLS-1$ 
+		case URI:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"URI"); //$NON-NLS-1$ 
+		case INET_ADDRESS:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"INET_ADDRESS"); //$NON-NLS-1$ 
+		case ENUMERATION:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"ENUMERATION"); //$NON-NLS-1$ 
+		case TYPE:
+			return Locale.getStringFrom(NAME_RESOURCE_FILE,"TYPE"); //$NON-NLS-1$ 
+		default:
+		}		
+		return Locale.getStringFrom(NAME_RESOURCE_FILE,"OTHER"); //$NON-NLS-1$ 
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @return {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+	/** Replies the Attribute type that corresponds to the
+	 * specified internal code.
+	 * 
+	 * @param type is an integer representing an attribute type.
+	 * @return the type that corresponds to the given integer.
+	 */
+	public static AttributeType fromInteger(int type) {
+		AttributeType[] vals = values();
+		if ((vals!=null)&&(type>=0)&&(type<vals.length))
+			return vals[type];
+		return OBJECT;
+	}
+
+	/** Replies the Attribute type that corresponds to the
+	 * specified value.
+	 * 
+	 *  @param value is the value to test.
+	 *  @return the type that corresponds to the given value.
+	 */
+	public static AttributeType fromValue(Object value) {
+		if (value!=null) {
+			if (value instanceof NullAttribute)
+				return ((NullAttribute)value).getType();
+			return fromClass(value.getClass());
+		}
+		return OBJECT;
+	}
+
+	/** Replies the Attribute type that corresponds to the
+	 * specified type.
+	 * 
+	 *  @param type is the type to test.
+	 *  @return the type that corresponds to the given value.
+	 */
+	public static AttributeType fromClass(Class<?> type) {
+		if (type!=null) {
+			if (byte.class.isAssignableFrom(type)) return INTEGER;
+			if (Byte.class.isAssignableFrom(type)) return INTEGER;
+			if (short.class.isAssignableFrom(type)) return INTEGER;
+			if (Short.class.isAssignableFrom(type)) return INTEGER;
+			if (int.class.isAssignableFrom(type)) return INTEGER;
+			if (Integer.class.isAssignableFrom(type)) return INTEGER;
+			if (long.class.isAssignableFrom(type)) return INTEGER;
+			if (Long.class.isAssignableFrom(type)) return INTEGER;
+			if (BigInteger.class.isAssignableFrom(type)) return INTEGER;
+			if (AtomicInteger.class.isAssignableFrom(type)) return INTEGER;
+			if (AtomicLong.class.isAssignableFrom(type)) return INTEGER;
+
+			if (Timestamp.class.isAssignableFrom(type)) return TIMESTAMP;
+			
+			if (float.class.isAssignableFrom(type)) return REAL;
+			if (double.class.isAssignableFrom(type)) return REAL;
+			if (Number.class.isAssignableFrom(type)) return REAL;
+
+			if (char.class.isAssignableFrom(type)) return STRING;
+			if (Character.class.isAssignableFrom(type)) return STRING;
+			if (CharSequence.class.isAssignableFrom(type)) return STRING;
+	
+			if (boolean.class.isAssignableFrom(type)) return BOOLEAN;
+			if (Boolean.class.isAssignableFrom(type)) return BOOLEAN;
+	
+			if (Date.class.isAssignableFrom(type)) return DATE;
+			if (Calendar.class.isAssignableFrom(type)) return DATE;
+	
+			if (Tuple3D.class.isAssignableFrom(type)) return POINT3D;
+
+			if (Tuple2D.class.isAssignableFrom(type)) return POINT;
+
+			if (Color.class.isAssignableFrom(type)) return COLOR;
+
+			if (UUID.class.isAssignableFrom(type)) return UUID;
+
+			if (java.net.URL.class.isAssignableFrom(type)) return URL;
+
+			if (java.net.URI.class.isAssignableFrom(type)) return URI;
+
+			if (Image.class.isAssignableFrom(type)) return IMAGE;
+
+			if (InetAddress.class.isAssignableFrom(type)) return INET_ADDRESS;
+			if (InetSocketAddress.class.isAssignableFrom(type)) return INET_ADDRESS;
+
+			if (type.isArray()) {
+				Class<?> elementType = type.getComponentType();
+				if (Point2D.class.isAssignableFrom(elementType)) return POLYLINE;
+				if (Point3D.class.isAssignableFrom(elementType)) return POLYLINE3D;
+			}
+
+
+			if (Enum.class.isAssignableFrom(type)) return ENUMERATION;
+
+			if (Class.class.isAssignableFrom(type)) return TYPE;
+		}
+		return OBJECT;
+	}
+
+	/** Replies if the specified value is an instanceof the type..
+	 * 
+	 *  @param value is the value to test.
+	 *  @return <code>true</code> if the given value is an instance of
+	 *  this attribute type, otherwise <code>false</code>.
+	 */
+	public boolean instanceOf(Object value) {
+		return this == fromValue(value);
+	}
+
+	/** Replies the default value for the specified type.
+	 * 
+	 * @return the default value.
+	 */
+	public Object getDefaultValue() {
+		switch(this) {
+		case INTEGER:
+			return new Long(0);
+		case REAL:
+			return new Double(0);
+		case STRING:
+			return new String();
+		case BOOLEAN:
+			return Boolean.FALSE;
+		case DATE:
+			return new Date();
+		case TIMESTAMP:
+			return new Timestamp(System.currentTimeMillis());
+		case POINT3D:
+			return new Point3f();
+		case POINT:
+			return new Point2f();
+		case COLOR:
+			return VectorToolkit.BLACK;
+		case UUID:
+			return java.util.UUID.fromString("00000000-0000-0000-0000-000000000000"); //$NON-NLS-1$
+		case URL:
+			return null;
+		case URI:
+			return null;
+		case POLYLINE3D:
+			return new Point3D[0];
+		case POLYLINE:
+			return new Point2D[0];
+		case OBJECT:
+			return null;
+		case IMAGE:
+			return null;
+		case INET_ADDRESS:
+			try {
+				return InetAddress.getLocalHost();
+			}
+			catch (UnknownHostException _) {
+				return null;
+			}
+		case ENUMERATION:
+			return null;
+		case TYPE:
+		default:
+			return Object.class;
+		}		
+	}
+
+	/**
+	 * Replies if this attribute type is
+	 * a base type, ie. a number, a boolean
+	 * or a string.
+	 * 
+	 * @return <code>true</code> if this type is a base type,
+	 * otherwise <code>false</code>
+	 */
+	public boolean isBaseType() {
+		return this==INTEGER
+			|| this==REAL
+			|| this==TIMESTAMP
+			|| this==BOOLEAN
+			|| this==STRING;
+	}
+
+	/**
+	 * Replies if this attribute type is
+	 * a number type.
+	 * A number type is always a base type.
+	 * 
+	 * @return <code>true</code> if this type is a number type,
+	 * otherwise <code>false</code>
+	 * @since 4.0
+	 */
+	public boolean isNumberType() {
+		return this==INTEGER
+			|| this==REAL
+			|| this==TIMESTAMP;
+	}
+
+	/**
+	 * Replies if a null value is allowed for this attribute type.
+	 * 
+	 * @return <code>true</code> if this type allows <code>null</code> value,
+	 * otherwise <code>false</code>
+	 */
+	public boolean isNullAllowed() {
+		return this==OBJECT
+			|| this==IMAGE
+			|| this==URI
+			|| this==URL
+			|| this==INET_ADDRESS
+			|| this==ENUMERATION;
+	}
+	
+	/** Replies if a value of the given attribute type may
+	 * be cast to a value of this attribute type.
+	 * <p>
+	 * Caution: even if isAssignableFrom is replying <code>true</code>,
+	 * the {@link AttributeValue#cast(AttributeType)} and
+	 * {@link AttributeValue#castAndSet(AttributeType, Object)} may fail
+	 * if the target type does not support a specifical value of the
+	 * source type. The isAssignableFrom function replies <code>true</code>
+	 * if a least one value of the source type is assignable to a value
+	 * of the target type.
+	 * 
+	 * @param type
+	 * @return <code>true</code> if a value of the given
+	 * <var>type</var> may be cast to a value of <code>this</code>;
+	 * otherwise <code>false</code>.
+	 * @since 4.0
+	 */
+	public boolean isAssignableFrom(AttributeType type) {
+		switch(this) {
+		case INTEGER:
+		case REAL:
+			return type==INTEGER || type==REAL || type==TIMESTAMP || type==STRING || type==DATE || type==BOOLEAN || type==COLOR || type==ENUMERATION ||  type==OBJECT;
+		case TIMESTAMP:
+			return type==INTEGER || type==REAL || type==TIMESTAMP || type==STRING || type==DATE || type==BOOLEAN || type==COLOR || type==OBJECT;
+		case BOOLEAN:
+			return type==BOOLEAN || type==STRING || type==INTEGER || type==TIMESTAMP || type==REAL || type==OBJECT;
+		case DATE:
+			return type==DATE || type==REAL || type==INTEGER || type==TIMESTAMP || type==STRING || type==OBJECT;
+		case POINT3D:
+		case POINT:
+			return type==POINT || type==POINT3D || type==COLOR || type==REAL || type==INTEGER || type==TIMESTAMP || type==DATE || type==STRING || type==OBJECT;
+		case COLOR:
+			return type==COLOR || type==POINT || type==POINT3D || type==STRING || type==INTEGER || type==REAL || type==TIMESTAMP || type==DATE || type==OBJECT;
+		case URL:
+			return type==URI || type==URL || type==INET_ADDRESS || type==STRING || type==OBJECT;
+		case URI:
+			return type==URI || type==URL || type==INET_ADDRESS || type==STRING || type==UUID || type==OBJECT;
+		case POLYLINE3D:
+		case POLYLINE:
+			return type==POLYLINE || type==POLYLINE3D || type==POINT || type==POINT3D || type==STRING || type==OBJECT;
+		case IMAGE:
+			return type==IMAGE || type==OBJECT;
+		case INET_ADDRESS:
+			return type==INET_ADDRESS || type==STRING || type==URL || type==URI  || type==OBJECT;
+		case ENUMERATION:
+			return type==ENUMERATION || type==STRING || type==OBJECT;
+		case TYPE:
+			return type==TYPE || type==STRING || type==OBJECT;
+		case UUID:
+		case STRING:
+		case OBJECT:
+			return true;
+		default:
+		}
+		return false;
+	}
+
+	/** Cast the specified value to corresponds to the
+	 * default storage standard for attributes.
+	 * 
+	 * @param obj is the object to cast
+	 * @return the casted value
+	 * @throws ClassCastException if is impossible to cast.
+	 * @throws NullPointerException if null value is not allowed.
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public Object cast(Object obj) {
+		if (obj instanceof NullAttribute) return null;
+		switch(this) {
+		case INTEGER:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj instanceof Enum<?>) return (long)((Enum<?>)obj).ordinal();
+			return ((Number)obj).longValue();
+		case REAL:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj instanceof Enum<?>) return (double)((Enum<?>)obj).ordinal();
+			return ((Number)obj).doubleValue();
+		case STRING:
+			if (obj==null) return ""; //$NON-NLS-1$
+			if (obj instanceof Enum<?>) {
+				Enum<?> enumValue = (Enum<?>)obj;
+				return enumValue.getClass().getCanonicalName()
+						+"." //$NON-NLS-1$
+						+enumValue.name();
+			}
+			return obj.toString();
+		case BOOLEAN:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			return Boolean.class.cast(obj);
+		case DATE:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj instanceof Number)
+				return new Date(((Number)obj).longValue());
+			if (obj instanceof Calendar) return ((Calendar)obj).getTime();
+			return Date.class.cast(obj);
+		case TIMESTAMP:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj instanceof Calendar) return ((Calendar)obj).getTimeInMillis();
+			if (obj instanceof Date) return ((Date)obj).getTime();
+			if (obj instanceof Number && !(obj instanceof Timestamp)) {
+				return new Timestamp(((Number)obj).longValue());
+			}
+			return Timestamp.class.cast(obj);
+		case POINT3D:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj instanceof Tuple3D && !(obj instanceof Point3D)) {
+				return new Point3f((Tuple3D)obj);
+			}
+			return Point3D.class.cast(obj);
+		case POINT:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj instanceof Tuple2D && !(obj instanceof Point2D)) {
+				return new Point2f((Tuple2D)obj);
+			}
+			return Point2D.class.cast(obj);
+		case COLOR:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj instanceof Number) {
+				return VectorToolkit.color(((Number)obj).intValue());
+			}
+			return Color.class.cast(obj);
+		case UUID:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			return UUID.class.cast(obj);
+		case URL:
+			// Possible ClassCastException
+			if (obj==null) return null;
+			if (obj instanceof java.net.URI) {
+				try {
+					return ((java.net.URI)obj).toURL();
+				}
+				catch (MalformedURLException e) {
+					//
+				}
+			}
+			if (obj instanceof InetAddress) {
+				try {
+					return new java.net.URL(AttributeConstants.DEFAULT_SCHEME.name(), ((InetAddress)obj).getHostAddress(), ""); //$NON-NLS-1$
+				}
+				catch (MalformedURLException e) {
+					//
+				}
+			}
+			if (obj instanceof InetSocketAddress) {
+				try {
+					return new java.net.URL(AttributeConstants.DEFAULT_SCHEME.name(), ((InetSocketAddress)obj).getAddress().getHostAddress(), ""); //$NON-NLS-1$
+				}
+				catch (MalformedURLException e) {
+					//
+				}
+			}
+			return java.net.URL.class.cast(obj);
+		case URI:
+			// Possible ClassCastException
+			if (obj==null) return null;
+			if (obj instanceof java.net.URL) {
+				try {
+					return ((java.net.URL)obj).toURI();
+				}
+				catch (URISyntaxException e) {
+					//
+				}
+			}
+			if (obj instanceof InetAddress) {
+				try {
+					return new java.net.URI(AttributeConstants.DEFAULT_SCHEME.name(), ((InetAddress)obj).getHostAddress(), ""); //$NON-NLS-1$
+				}
+				catch (URISyntaxException e) {
+					//
+				}
+			}
+			if (obj instanceof InetSocketAddress) {
+				try {
+					return new java.net.URI(AttributeConstants.DEFAULT_SCHEME.name(), ((InetSocketAddress)obj).getAddress().getHostAddress(), ""); //$NON-NLS-1$
+				}
+				catch (URISyntaxException e) {
+					//
+				}
+			}
+			return java.net.URI.class.cast(obj);
+		case POLYLINE3D:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj.getClass().isArray()) {
+				Class<?> elementType = obj.getClass().getComponentType();
+				if (Tuple3D.class.isAssignableFrom(elementType) &&
+					!Point3D.class.isAssignableFrom(elementType)) {
+					int length = Array.getLength(obj);
+					Point3D[] tab = new Point3D[length];
+					for(int i=0; i<length; ++i)
+						tab[i] = new Point3f((Tuple3D)Array.get(obj, i));
+					return tab;
+				}
+			}
+			return Point3D[].class.cast(obj);
+		case POLYLINE:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj.getClass().isArray()) {
+				Class<?> elementType = obj.getClass().getComponentType();
+				if (Tuple2D.class.isAssignableFrom(elementType) &&
+					!Point2D.class.isAssignableFrom(elementType)) {
+					int length = Array.getLength(obj);
+					Point2D[] tab = new Point2D[length];
+					for(int i=0; i<length; ++i)
+						tab[i] = new Point2f((Tuple2D)Array.get(obj, i));
+					return tab;
+				}
+			}
+			return Point2D[].class.cast(obj);
+		case IMAGE:
+			if (obj==null) return null;
+			return Image.class.cast(obj);
+		case OBJECT:
+			if (obj==null) return null;
+			break;
+		case INET_ADDRESS:
+			if (obj==null) return null;
+			if (obj instanceof InetSocketAddress) {
+				return ((InetSocketAddress)obj).getAddress();
+			}
+			if (obj instanceof java.net.URL) {
+				java.net.URL url = (java.net.URL)obj;
+				try {
+					return InetAddress.getByName(url.getHost());
+				}
+				catch (UnknownHostException _) {
+					//
+				}
+			}
+			if (obj instanceof java.net.URI) {
+				java.net.URI uri = (java.net.URI)obj;
+				try {
+					return InetAddress.getByName(uri.getHost());
+				}
+				catch (UnknownHostException _) {
+					//
+				}
+			}
+			if (obj instanceof CharSequence) {
+				try {
+					String ipStr = obj.toString();
+					int index = ipStr.lastIndexOf("/"); //$NON-NLS-1$
+					if (index>=0) {
+						try {
+							return InetAddress.getByName(ipStr.substring(index+1));
+						}
+						catch (UnknownHostException _) {
+							//
+						}
+					}
+					return InetAddress.getByName(ipStr);
+				}
+				catch (UnknownHostException _) {
+					//
+				}
+			}
+			return InetAddress.class.cast(obj);
+		case ENUMERATION:
+			if (obj==null) return null;
+			if (obj instanceof CharSequence) {
+				String enumStr = obj.toString();
+				int index = enumStr.lastIndexOf('.');
+				if (index>0) {
+					String enumName = enumStr.substring(0, index);
+					String constantName = enumStr.substring(index+1);
+					try {
+						Class type = Class.forName(enumName);
+						if (Enum.class.isAssignableFrom(type)) {
+							 Enum<?> v = Enum.valueOf(type, constantName.toUpperCase());
+							 if (v!=null) return v;
+						}
+					}
+					catch(Throwable _) {
+						//
+					}
+				}
+			}
+			return Enum.class.cast(obj);
+		case TYPE:
+			// Possible ClassCastException
+			if (obj==null) throw new NullPointerException();
+			if (obj instanceof CharSequence) {
+				try {
+					return Class.forName(((CharSequence)obj).toString());
+				}
+				catch (ClassNotFoundException e) {
+					//
+				}
+			}
+			return Class.class.cast(obj);
+		default:
+			throw new ClassCastException();
+		}
+		return obj;
+	}
+	
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValue.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValue.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValue.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,674 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.UUID;
+
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Point3D;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+
+/**
+ * This class contains a metadata value.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface AttributeValue {
+
+	/**
+	 * Replies a comparator suitable for attribute values.
+	 * 
+	 * @return a comparator, never <code>null</code>
+	 */
+	public Comparator<? extends AttributeValue> valueComparator();
+
+	/**
+	 * Replies if this attribute type is
+	 * a base type, ie. a number, a boolean
+	 * or a string.
+	 * <p>
+	 * The following code is always <code>true</code>:<br>
+	 * <code>isObjectValue() == !isBaseValue()</code>
+	 * 
+	 * @return <code>true</code> if this attribute is containing a base type value,
+	 * otherwise <code>false</code>
+	 * @see #isNullAllowed()
+	 * @see #isObjectValue()
+	 */
+	public boolean isBaseType();
+
+	/**
+	 * Replies the type of this metadata.
+	 * 
+	 * @return the type of the attribute
+	 */
+	public AttributeType getType() ; 
+	
+	/**
+	 * Change the type of this attribute.
+	 * <p>
+	 * The exception will be generated in case
+	 * the current value could not be casted
+	 * to the new type.
+	 * 
+	 * @param type is the new type of this attribute
+	 * @throws InvalidAttributeTypeException if the current value was incompatible with the given type. 
+	 */
+	public void setType(AttributeType type) throws InvalidAttributeTypeException; 
+
+	/**
+	 * Change the type of this attribute.
+	 * <p>
+	 * The value could be lost in case the type was incompatible
+	 * with the value.
+	 * 
+	 * @param type is the new type of this attribute
+	 * @return <code>true</code> if the cast was sucessfully done,
+	 *         otherwhise, if the value was lost because of the
+	 *         cast operation.
+	 */
+	public boolean cast(AttributeType type); 
+
+	/**
+	 * Change the type of this attribute and set its value.
+	 * 
+	 * @param type is the new type of this attribute
+	 * @param value is the new value.
+	 */
+	public void castAndSet(AttributeType type, Object value); 
+
+	/** Replies the value attribute stored in the implementation of this interface.
+	 * In opposite than {@link #getJavaObject()}, this function replies
+	 * the value for all attribute type.
+	 * 
+	 * @return the raw value of this attribute
+	 * @throws InvalidAttributeTypeException
+	 * @throws AttributeNotInitializedException
+	 */
+	public Object getValue() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/** Replies the type of the internal value of this implementation of AttributeValue.
+	 * 
+	 * @return the type of the value stored inside this attribute value implementation.
+	 * @since 4.0
+	 */
+	public Class<?> getInternalStorageType();
+
+	/** The this value with the content of the specified one.
+	 * 
+	 * @param value
+	 */
+	public void setValue(AttributeValue value);
+	
+	/** The this value with the content of the specified one.
+	 * <p>
+	 * The type of the attribute will be detected from the type
+	 * of the object.
+	 * 
+	 * @param value
+	 */
+	public void setValue(Object value);
+
+	/** Set the value to its default.
+	 */
+	public void setToDefault() ;
+	
+	/** Set the value to its default if not init.
+	 */
+	public void setToDefaultIfUninitialized() ;
+
+	/**
+	 * Replies the value of this metadata.
+	 *
+	 * @return the value
+	 * @throws InvalidAttributeTypeException
+	 * @throws AttributeNotInitializedException
+	 */
+	public long getInteger() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param value
+	 */
+	public void setInteger(int value);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param value
+	 */
+	public void setInteger(long value);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return the value
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public double getReal() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param value
+	 */
+	public void setReal(double value);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return the value
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public String getString() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+	
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param value
+	 */
+	public void setString(String value);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return the value
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Date getDate() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param value
+	 */
+	public void setDate(Date value);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return the value
+	 * @throws InvalidAttributeTypeException
+	 * @throws AttributeNotInitializedException
+	 */
+	public boolean getBoolean() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param value
+	 */
+	public void setBoolean(boolean value);
+
+	/**
+	 * Replies of the value of this attribute is
+	 * a data object ie, java object or icon.
+	 * <p>
+	 * The following code is always <code>true</code>:<br>
+	 * <code>isObjectValue() == !isBaseValue()</code>
+	 * 
+	 * @return <code>true</code> if this attribute contains a object as value (ie, not a base type),
+	 * otherwise <code>false</code>
+	 * @see #isBaseType()
+	 * @see #isNullAllowed()
+	 */
+	public boolean isObjectValue();
+
+	/**
+	 * Replies the value of this metadata.
+	 * In opposite than {@link #getValue()}, this function replies
+	 * the value only if this attribute value if of type
+	 * {@link AttributeType#OBJECT}.
+	 *
+	 * @param <T> is the type of the value to reply
+	 * @return the value
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 * @see #getValue()
+	 */
+	public <T extends Object> T getJavaObject() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param <T> is the type of the new value
+	 * @param value
+	 */
+	public <T extends Object> void setJavaObject(T value);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return a timestamp with a precision in milliseconds
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public long getTimestamp() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param value
+	 */
+	public void setTimestamp(long value);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return a 3d point
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Point3D getPoint3D() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param p
+	 */
+	public void setPoint3D(Point3D p);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param x
+	 * @param y
+	 * @param z
+	 */
+	public void setPoint3D(float x, float y, float z);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return a 2d point
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Point2D getPoint() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param p
+	 */
+	public void setPoint(Point2D p);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param x
+	 * @param y
+	 */
+	public void setPoint(float x, float y);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return a color
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Color getColor() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param c
+	 */
+	public void setColor(Color c);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param r
+	 * @param g
+	 * @param b
+	 */
+	public void setColor(float r, float g, float b);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param r
+	 * @param g
+	 * @param b
+	 * @param a
+	 */
+	public void setColor(float r, float g, float b, float a);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param r
+	 * @param g
+	 * @param b
+	 */
+	public void setColor(int r, int g, int b);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param r
+	 * @param g
+	 * @param b
+	 * @param a
+	 */
+	public void setColor(int r, int g, int b, int a);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return an icon
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Image getImage() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param c
+	 */
+	public void setImage(Image c);
+	
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return an uuid
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 * @since 4.0
+	 */
+	public UUID getUUID() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param u
+	 * @since 4.0
+	 */
+	public void setUUID(UUID u);
+	
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return an url
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 * @since 4.0
+	 */
+	public URL getURL() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param u
+	 * @since 4.0
+	 */
+	public void setURL(URL u);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return an uri
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 * @since 4.0
+	 */
+	public URI getURI() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param u
+	 * @since 4.0
+	 */
+	public void setURI(URI u);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return a list of 3d points
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Point3D[] getPolyline3D() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param p
+	 */
+	public void setPolyline3D(Point3D... p);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param p
+	 */
+	public void setPolyline3D(Collection<? extends Point3D> p);
+
+	/**
+	 * Add a point to the end of the polyline
+	 * 
+	 * @param p
+	 */
+	public void addToPolyline3D(Point3D... p);
+
+	/**
+	 * Add a point to the end of the polyline
+	 * 
+	 * @param p
+	 */
+	public void addToPolyline3D(Collection<? extends Point3D> p);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return a list of 2d points
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Point2D[] getPolyline() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param p
+	 */
+	public void setPolyline(Point2D... p);
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param p
+	 */
+	public void setPolyline(Collection<? extends Point2D> p);
+
+	/**
+	 * Add a point to the end of the polyline
+	 * 
+	 * @param p
+	 */
+	public void addToPolyline(Point2D... p);
+
+	/**
+	 * Add a point to the end of the polyline
+	 * 
+	 * @param p
+	 */
+	public void addToPolyline(Collection<? extends Point2D> p);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return an Internet address.
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public InetAddress getInetAddress() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param a
+	 */
+	public void setInetAddress(InetAddress a);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return an enumeration.
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Enum<?> getEnumeration() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @param <T> is the type of the enumeration to reply.
+	 * @param type is the type of the enumeration to reply.
+	 * @return an enumeration.
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public <T extends Enum<T>> T getEnumeration(Class<T> type) throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param e
+	 */
+	public void setEnumeration(Enum<?> e);
+
+	/**
+	 * Replies the value of this metadata.
+	 * 
+	 * @return a Java type.
+	 * @throws AttributeNotInitializedException
+	 * @throws InvalidAttributeTypeException
+	 */
+	public Class<?> getJavaClass() throws InvalidAttributeTypeException, AttributeNotInitializedException;
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param e
+	 */
+	public void setJavaClass(Class<?> e);
+
+	/**
+	 * Replies if a value was affected to this attribute.
+	 * 
+	 * @return <code>true</code> if this attribute is containing a value,
+	 * otherwise <code>false</code>
+	 */
+	public boolean isAssigned();
+
+	/**
+	 * Replies if a null value is allowed for this attribute.
+	 * <p>
+	 * If {@link #isBaseType()} replies <code>true</code>,
+	 * this function must always replies <code>false</code>.
+	 * 
+	 * @return <code>true</code> if <code>null</code> is assigned to this attribute,
+	 * otherwise <code>false</code>
+	 * @see #isBaseType()
+	 * @see #isObjectValue()
+	 */
+	public boolean isNullAllowed();
+
+	/**
+	 * Set this attribute value uninitialized.
+	 */
+	public void uninitializeValue();
+
+	/** Force this attribute to put its value into a storage system.
+	 * <p>
+	 * By default, this function does nothing. It is dependant of the application
+	 * implementation.
+	 * 
+	 * @return <code>true</code> if the value was written, otherwhise <code>false</code>
+	 */
+	public boolean flush();
+
+	/** Replies if a value of the given attribute type may
+	 * be cast to a value of this attribute type.
+	 * <p>
+	 * Caution: even if isAssignableFrom is replying <code>true</code>,
+	 * the {@link AttributeValue#cast(AttributeType)} and
+	 * {@link AttributeValue#castAndSet(AttributeType, Object)} may fail
+	 * if the target type does not support a specifical value of the
+	 * source type. The isAssignableFrom function replies <code>true</code>
+	 * if a least one value of the source type is assignable to a value
+	 * of the target type.
+	 * <p>
+	 * This function is equivalent to:
+	 * <code>this.getType().isAssignableFrom(type)</code>
+	 * 
+	 * @param type
+	 * @return <code>true</code> if a value of the given
+	 * <var>type</var> may be cast to a value of the same type as this;
+	 * otherwise <code>false</code>.
+	 * @since 4.0
+	 */
+	public boolean isAssignableFrom(AttributeType type);
+	
+	/** Replies if a value of the given attribute type may
+	 * be cast to a value of this attribute type.
+	 * <p>
+	 * Caution: even if isAssignableFrom is replying <code>true</code>,
+	 * the {@link AttributeValue#cast(AttributeType)} and
+	 * {@link AttributeValue#castAndSet(AttributeType, Object)} may fail
+	 * if the target type does not support a specifical value of the
+	 * source type. The isAssignableFrom function replies <code>true</code>
+	 * if a least one value of the source type is assignable to a value
+	 * of the target type.
+	 * <p>
+	 * This function is equivalent to:
+	 * <code>this.getType().isAssignableFrom(value.getType())</code>
+	 * 
+	 * @param value
+	 * @return <code>true</code> if the given value may be cast to
+	 * a value of the same type as this;
+	 * otherwise <code>false</code>.
+	 * @since 4.0
+	 */
+	public boolean isAssignableFrom(AttributeValue value);
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValueComparator.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValueComparator.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValueComparator.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,82 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.util.Comparator;
+
+
+
+/**
+ * This class permits to compare to {@link AttributeValue}.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeValueComparator implements Comparator<AttributeValue> {
+	
+    /**
+     * Compares its two arguments for order.  Returns a negative integer,
+     * zero, or a positive integer as the first argument is less than, equal
+     * to, or greater than the second.<p>
+     *
+     * In the foregoing description, the notation
+     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
+     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
+     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
+     * <i>expression</i> is negative, zero or positive.<p>
+     *
+     * The implementor must ensure that <tt>sgn(compare(x, y)) ==
+     * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
+     * implies that <tt>compare(x, y)</tt> must throw an exception if and only
+     * if <tt>compare(y, x)</tt> throws an exception.)<p>
+     *
+     * The implementor must also ensure that the relation is transitive:
+     * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
+     * <tt>compare(x, z)&gt;0</tt>.<p>
+     *
+     * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt>
+     * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
+     * <tt>z</tt>.<p>
+     *
+     * It is generally the case, but <i>not</i> strictly required that
+     * <tt>(compare(x, y)==0) == (x.equals(y))</tt>.  Generally speaking,
+     * any comparator that violates this condition should clearly indicate
+     * this fact.  The recommended language is "Note: this comparator
+     * imposes orderings that are inconsistent with equals."
+     *
+     * @param arg0 the first object to be compared.
+     * @param arg1 the second object to be compared.
+     * @return a negative integer, zero, or a positive integer as the
+     * 	       first argument is less than, equal to, or greater than the
+     *	       second.
+     * @throws ClassCastException if the arguments' types prevent them from
+     * 	       being compared by this comparator.
+     */
+	@Override
+	public int compare(AttributeValue arg0, AttributeValue arg1) {
+		return AttributeValueImpl.compareValues(arg0, arg1);
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValueImpl.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValueImpl.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/AttributeValueImpl.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,2737 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.lang.reflect.Array;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Locale;
+import java.util.UUID;
+
+import org.arakhne.afc.math.continous.object2d.Point2f;
+import org.arakhne.afc.math.continous.object3d.Point3f;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Point3D;
+import org.arakhne.afc.math.generic.Tuple2D;
+import org.arakhne.afc.math.generic.Tuple3D;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+import org.arakhne.afc.ui.vector.VectorToolkit;
+
+/**
+ * This class contains an attribute value.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeValueImpl implements AttributeValue, AttributeConstants {
+
+	/** Replies the best attribute value that is representing
+	 * the given text.
+	 * 
+	 * @param text
+	 * @return the attribute value, never <code>null</code>.
+	 */
+	public static AttributeValueImpl parse(String text) {
+		AttributeValueImpl value = new AttributeValueImpl(text);
+		if (text!=null && !text.isEmpty()) {
+			Object binValue;
+			for(AttributeType type : AttributeType.values()) {
+				try {
+					binValue = null;
+					switch(type) {
+					case BOOLEAN:
+						binValue = value.getBoolean();
+						break;
+					case COLOR:
+						binValue = parseColor((String)value.value, true);
+						break;
+					case DATE:
+						binValue = value.getDate();
+						break;
+					case ENUMERATION:
+						binValue = value.getEnumeration();
+						break;
+					case IMAGE:
+						binValue = value.getImage();
+						break;
+					case INET_ADDRESS:
+						binValue = value.getInetAddress();
+						break;
+					case INTEGER:
+						binValue = value.getInteger();
+						break;
+					case OBJECT:
+						binValue = value.getJavaObject();
+						break;
+					case POINT:
+						binValue = parsePoint((String)value.value, true);
+						break;
+					case POINT3D:
+						binValue = parsePoint3D((String)value.value, true);
+						break;
+					case POLYLINE:
+						binValue = parsePolyline((String)value.value, true);
+						break;
+					case POLYLINE3D:
+						binValue = parsePolyline3D((String)value.value, true);
+						break;
+					case REAL:
+						binValue = value.getReal();
+						break;
+					case STRING:
+						binValue = value.getString();
+						break;
+					case TIMESTAMP:
+						binValue = value.getTimestamp();
+						break;
+					case TYPE:
+						binValue = value.getJavaClass();
+						break;
+					case URI:
+						binValue = parseURI((String)value.value);
+						break;
+					case URL:
+						binValue = value.getURL();
+						break;
+					case UUID:
+						binValue = parseUUID((String)value.value);
+						break;
+					default:
+						//
+					}
+					if (binValue!=null) {
+						return new AttributeValueImpl(type, binValue);
+					}
+				}
+				catch(Throwable _) {
+					//
+				}
+			}
+		}
+		return value;
+	}
+	
+	/** Compare the two specified values.
+	 * 
+	 * @param arg0
+	 * @param arg1
+	 * @return replies a negative value if <var>arg0</var> is lesser than
+	 * <var>arg1</var>, a positive value if <var>arg0</var> is greater than
+	 * <var>arg1</var>, or <code>0</code> if they are equal.
+	 * @see AttributeValueComparator
+	 */
+	public static int compareValues(AttributeValue arg0, AttributeValue arg1) {
+		if (arg0==arg1) return 0;
+		if (arg0==null) return Integer.MAX_VALUE;
+		if (arg1==null) return Integer.MIN_VALUE;
+		
+		Object v0, v1;
+		
+		try {
+			v0 = arg0.getValue();
+		}
+		catch (Exception _) {
+			v0 = null;
+		}
+
+		try {
+			v1 = arg1.getValue();
+		}
+		catch (Exception _) {
+			v1 = null;
+		}
+
+		return compareRawValues(v0, v1);
+	}
+	
+	/** Compare the internal objects of two specified values
+	 * 
+	 * @param arg0
+	 * @param arg1
+	 * @return replies a negative value if <var>arg0</var> is lesser than
+	 * <var>arg1</var>, a positive value if <var>arg0</var> is greater than
+	 * <var>arg1</var>, or <code>0</code> if they are equal.
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	private static int compareRawValues(Object arg0, Object arg1) {
+		if (arg0==arg1) return 0;
+		if (arg0==null) return Integer.MAX_VALUE;
+		if (arg1==null) return Integer.MIN_VALUE;
+		
+		if ((arg0 instanceof Number)&&(arg1 instanceof Number))
+			return Double.compare(((Number)arg0).doubleValue(),((Number)arg1).doubleValue());
+
+		try {
+			if (arg0 instanceof Comparable<?>)
+				return ((Comparable)arg0).compareTo(arg1);
+		}
+		catch(RuntimeException _) {
+			//
+		}
+		
+		try {
+			if (arg1 instanceof Comparable<?>)
+				return - ((Comparable)arg1).compareTo(arg0);
+		}
+		catch(RuntimeException _) {
+			//
+		}
+		
+		if (arg0.equals(arg1)) return 0;
+		
+		String sv0 = arg0.toString();
+		String sv1 = arg1.toString();
+
+		if (sv0==sv1) return 0;
+		if (sv0==null) return Integer.MAX_VALUE;
+		if (sv1==null) return Integer.MIN_VALUE;
+		
+		return sv0.compareTo(sv1);
+	}
+
+	/**
+	 * Type of the metadata.
+	 */
+	private AttributeType type;
+	
+	/**
+	 * Value of the metadata.
+	 */
+	private Object value;
+	
+	/** Indicates if this attribute was assigned.
+	 */
+	private boolean assigned = false;
+
+	/**
+	 * Uninitialized value.
+	 */
+	public AttributeValueImpl() {
+		this.type = AttributeType.OBJECT;
+		this.value = this.type.getDefaultValue();
+	}
+
+	/**
+	 * Uninitialized value.
+	 * 
+	 * @param type is the type of the value.
+	 */
+	public AttributeValueImpl(AttributeType type) {
+		this.type = type;
+		this.value = null;
+		this.assigned = false;
+	}
+	
+	/**
+	 * @param value is the value to initialize this new instance.
+	 */
+	public AttributeValueImpl(AttributeValue value) {
+		if (value!=null) {
+			this.type = value.getType();
+			try {
+				this.value = value.getValue();
+				this.assigned = isNullAllowed() || (this.value!=null);
+			}
+			catch (AttributeException _) {
+				this.value = null;
+				this.assigned = false;
+			}
+		}
+		else {
+			this.value = null;
+			this.assigned = false;
+		}		
+	}
+
+	/**
+	 * @param type is the type of this value.
+	 * @param rawValue is the value.
+	 */
+	public AttributeValueImpl(AttributeType type, Object rawValue) {
+		this.type = type;
+		if (rawValue==null) {
+			this.value = rawValue;
+		}
+		else {
+			try {
+				this.value = type.cast(rawValue);
+			}
+			catch(Exception _) {
+				this.value = null;
+			}
+		}
+		this.assigned = this.value!=null;
+	}
+	
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(boolean value) {
+		this.type = AttributeType.BOOLEAN;
+		this.value = new Boolean(value);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Color value) {
+		this.type = AttributeType.COLOR;
+		this.value = (value!=null) ? VectorToolkit.color(value.getRed(), value.getGreen(), value.getBlue(), value.getAlpha()) : null;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(UUID value) {
+		this.type = AttributeType.UUID;
+		this.value = (value!=null) ? new UUID(value.getMostSignificantBits(), value.getLeastSignificantBits()) : null;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(URL value) {
+		this.type = AttributeType.URL;
+		try {
+			this.value = (value!=null) ? new URL(value.toExternalForm()) : null;
+		}
+		catch (MalformedURLException e) {
+			this.value = null;
+		}
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(URI value) {
+		this.type = AttributeType.URI;
+		try {
+			this.value = (value!=null) ? new URI(value.toASCIIString()) : null;
+		}
+		catch (URISyntaxException e) {
+			this.value = null;
+		}
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(InetAddress value) {
+		this.type = AttributeType.INET_ADDRESS;
+		this.value = (value!=null) ? value : null;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(InetSocketAddress value) {
+		this.type = AttributeType.INET_ADDRESS;
+		this.value = (value!=null) ? value.getAddress() : null;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Enum<?> value) {
+		this.type = AttributeType.ENUMERATION;
+		this.value = (value!=null) ? value : null;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Class<?> value) {
+		this.type = AttributeType.TYPE;
+		this.value = (value!=null) ? value : null;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Date value) {
+		this.type = AttributeType.DATE;
+		this.value = (value!=null) ? new Date(value.getTime()) : null;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(float value) {
+		this.type = AttributeType.REAL;
+		this.value = new Double(value);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(double value) {
+		this.type = AttributeType.REAL;
+		this.value = new Double(value);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Image value) {
+		this.type = AttributeType.IMAGE;
+		this.value = value;
+		this.assigned = true;
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(int value) {
+		this.type = AttributeType.INTEGER;
+		this.value = new Long(value);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(long value) {
+		this.type = AttributeType.INTEGER;
+		this.value = new Long(value);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Point2D value) {
+		this.type = AttributeType.POINT;
+		this.value = value;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param x is the value.
+	 * @param y is the value.
+	 */
+	public AttributeValueImpl(float x, float y) {
+		this.type = AttributeType.POINT;
+		this.value = new Point2f(x,y);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param x is the value.
+	 * @param y is the value.
+	 */
+	public AttributeValueImpl(double x, double y) {
+		this.type = AttributeType.POINT;
+		this.value = new Point2f(x,y);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Point3D value) {
+		this.type = AttributeType.POINT3D;
+		this.value = value;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param x is the value.
+	 * @param y is the value.
+	 * @param z is the value.
+	 */
+	public AttributeValueImpl(float x, float y, float z) {
+		this.type = AttributeType.POINT3D;
+		this.value = new Point3f(x,y,z);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param x is the value.
+	 * @param y is the value.
+	 * @param z is the value.
+	 */
+	public AttributeValueImpl(double x, double y, double z) {
+		this.type = AttributeType.POINT3D;
+		this.value = new Point3f(x,y,z);
+		this.assigned = true;
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(String value) {
+		this.type = AttributeType.STRING;
+		this.value = value;
+		this.assigned = (value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Point2D[] value) {
+		this.type = AttributeType.POLYLINE;
+		this.value = value;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Point3D[] value) {
+		this.type = AttributeType.POLYLINE3D;
+		this.value = value;
+		this.assigned = (this.value!=null);
+	}
+
+	/**
+	 * @param value is the value.
+	 */
+	public AttributeValueImpl(Object value) {
+		AttributeType detectedType = AttributeType.fromValue(value);
+		this.type = detectedType;
+		this.value = detectedType.cast(value);
+		this.assigned = isNullAllowed() || (this.value!=null);
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @param o {@inheritDoc}
+	 * @return {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof AttributeValue) {
+			return compareValues(this, (AttributeValue)o)==0;
+		}
+		return compareRawValues(this.value, o) == 0;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+        int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + (this.value!=null ? this.value.hashCode() : 0);
+        return result;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @return {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder str = new StringBuilder();
+		str.append("["); //$NON-NLS-1$
+		str.append((this.value==null)
+				? "???" //$NON-NLS-1$
+				: this.value.toString());
+		str.append(":"); //$NON-NLS-1$
+		str.append(this.type.toString());
+		str.append("]"); //$NON-NLS-1$
+		return str.toString();
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean isAssignableFrom(AttributeType type) {
+		return getType().isAssignableFrom(type);
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean isAssignableFrom(AttributeValue value) {
+		return getType().isAssignableFrom(value.getType());
+	}
+
+	/** Replies if this value was assigned and
+	 * supposes that the <code>null</code> value is
+	 * allowed.
+	 *
+	 * @return <code>true</code> if the value is not assigned or equals to <code>null</code>.
+	 */
+	private boolean isNotAssignedOrNull() {
+		return ((!this.assigned)||(this.value==null));
+	}
+	
+	/** Assert that the attribute value was assigned.
+	 */
+	private void assertAssigned() throws AttributeNotInitializedException {
+		if ((this.type==null)||(!this.assigned)) throw new AttributeNotInitializedException();
+	}
+
+	/** Assert that the attribute value was assigned and not <code>null</code>.
+	 * 
+	 * @throws AttributeNotInitializedException
+	 */
+	protected void assertAssignedAndNotNull() throws AttributeNotInitializedException {
+		if ((this.type==null)||(!this.assigned)||(this.value==null)) throw new AttributeNotInitializedException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean isBaseType() {
+		return this.type.isBaseType();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean isNullAllowed() {
+		return this.type.isNullAllowed();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public AttributeType getType() {
+		return this.type;
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setType(AttributeType type) throws InvalidAttributeTypeException {
+		try {
+			switch(type) {
+			case INTEGER:
+				this.value = new Long(getInteger()); break;
+			case REAL:
+				this.value = new Double(getReal()); break;
+			case STRING:
+				this.value = getString(); break;
+			case BOOLEAN:
+				this.value = new Boolean(getBoolean()); break;
+			case DATE:
+				this.value = getDate(); break;
+			case TIMESTAMP:
+				this.value = new Timestamp(getTimestamp()); break;
+			case OBJECT:
+				this.value = getJavaObject(); break;
+			case POINT:
+				this.value = getPoint(); break;
+			case POINT3D:
+				this.value = getPoint3D(); break;
+			case COLOR:
+				this.value = getColor(); break;
+			case UUID:
+				this.value = getUUID(); break;
+			case IMAGE:
+				this.value = getImage(); break;
+			case POLYLINE:
+				this.value = getPolyline(); break;
+			case POLYLINE3D:
+				this.value = getPolyline3D(); break;
+			case URI:
+				this.value = getURI(); break;
+			case URL:
+				this.value = getURL(); break;
+			case INET_ADDRESS:
+				this.value = getInetAddress(); break;
+			case ENUMERATION:
+				this.value = getEnumeration(); break;
+			case TYPE:
+				this.value = getJavaClass(); break;
+			default:
+				throw new InvalidAttributeTypeException();
+			}			
+		}
+		catch(NumberFormatException ex) {
+			throw new InvalidAttributeTypeException();
+		}
+		catch (AttributeNotInitializedException e) {
+			this.value = type.getDefaultValue();
+		}
+		this.type = type;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean cast(AttributeType attrType) {
+		boolean b = true;
+		try {
+			setType(attrType);
+		}
+		catch(InvalidAttributeTypeException ex) {
+			this.value = attrType.getDefaultValue();
+			b = false;
+		}
+		this.type = attrType;
+		return b;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void castAndSet(AttributeType attrType, Object attrValue) {
+		try {
+			if (attrValue instanceof AttributeValue) {
+				this.type = ((AttributeValue)attrValue).getType();
+				try {
+					this.value = ((AttributeValue)attrValue).getValue();
+					this.assigned = true;
+				}
+				catch (AttributeNotInitializedException e) {
+					this.value = attrType.getDefaultValue();
+					this.assigned = true;
+				}
+			}
+			else {
+				this.type = attrType;
+				this.value = attrType.cast(attrValue);
+				this.assigned = true;
+			}
+			if (attrValue!=null) {
+				setType(attrType);
+			}
+			else {
+				this.value = attrType.getDefaultValue();
+				this.assigned = true;
+			}
+		}
+		catch(InvalidAttributeTypeException ex) {
+			this.value = attrType.getDefaultValue();
+			this.assigned = true;
+		}
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Object getValue() throws InvalidAttributeTypeException, AttributeNotInitializedException{
+		assertAssigned();
+		return this.value;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public final Class<?> getInternalStorageType() {
+		switch(this.type) {
+		case BOOLEAN:
+			return Boolean.class;
+		case COLOR:
+			return Color.class;
+		case DATE:
+			return Date.class;
+		case ENUMERATION:
+			return Enum.class;
+		case IMAGE:
+			return Image.class;
+		case INET_ADDRESS:
+			return InetAddress.class;
+		case INTEGER:
+			return Long.class;
+		case OBJECT:
+			return Object.class;
+		case POINT:
+			return Point2D.class;
+		case POINT3D:
+			return Point3D.class;
+		case POLYLINE:
+			return Point2D[].class;
+		case POLYLINE3D:
+			return Point3D[].class;
+		case REAL:
+			return Double.class;
+		case STRING:
+			return String.class;
+		case TIMESTAMP:
+			return Timestamp.class;
+		case TYPE:
+			return Class.class;
+		case URI:
+			return URI.class;
+		case URL:
+			return URL.class;
+		case UUID:
+			return UUID.class;
+		default:
+		}
+		return null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setValue(AttributeValue value) {
+		this.type = value.getType();
+		try {
+			this.assigned = value.isAssigned();
+			this.value = value.getValue();
+		}
+		catch (AttributeException e) {
+			this.value = this.type.getDefaultValue();
+		}
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setValue(Object value) {
+		AttributeType detectedType = AttributeType.fromValue(value);
+		this.value = detectedType.cast(value);
+		this.assigned = (this.value!=null);
+	}
+
+	/** Set this value with the content of the specified one.
+	 * <p>
+	 * The type of the attribute will be NOT detected from the type
+	 * of the object. It means that it is not changed by this function.
+	 * The given value must be compatible with internal representation
+	 * of the attribute implementation.
+	 * 
+	 * @param value is the raw value to put inside this attribute value.
+	 */
+	protected void setInternalValue(Object value) {
+		this.value = value;
+		this.assigned = (this.value!=null);
+	}
+
+	/** Set this value with the content of the specified one.
+	 * <p>
+	 * The type of the attribute will be NOT detected from the type
+	 * of the object. It means that it will be equal to the given type,
+	 * even if the given value is incompatible.
+	 * The given value must be compatible with internal representation
+	 * of the attribute implementation.
+	 * 
+	 * @param value is the raw value to put inside this attribute value.
+	 * @param type is the type of the value.
+	 */
+	protected void setInternalValue(Object value, AttributeType type) {
+		this.value = value;
+		this.assigned = (this.value!=null);
+		this.type = type;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setToDefault() {
+		this.assigned = true;
+		this.value = this.type.getDefaultValue();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setToDefaultIfUninitialized() {
+		if (!isAssigned()) setToDefault();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public long getInteger() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case INTEGER:
+				return ((Long)this.value).longValue();
+			case TIMESTAMP:
+				return ((Timestamp)this.value).longValue();
+			case REAL:
+				return ((Double)this.value).longValue();
+			case STRING:
+				return Long.parseLong((String)this.value);
+			case DATE:
+				return ((Date)this.value).getTime();
+			case BOOLEAN:
+				return ((Boolean)this.value).booleanValue() ? 1 : 0;
+			case COLOR:
+				return ((Color)this.value).getRGB();
+			case OBJECT:
+				if (this.value instanceof Number)
+					return ((Number)this.value).longValue();
+				break;
+			case ENUMERATION:
+				if (this.value instanceof Enum<?>)
+					return ((Enum<?>)this.value).ordinal();
+				break;
+			case IMAGE:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case TYPE:
+				break;
+			default:
+				throw new InvalidAttributeTypeException();
+			}
+		}
+		catch(NumberFormatException _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setInteger(int value) {
+		this.value = new Long(value);
+		this.type = AttributeType.INTEGER;
+		this.assigned = true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setInteger(long value) {
+		this.value = new Long(value);
+		this.type = AttributeType.INTEGER;
+		this.assigned = true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public double getReal() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case INTEGER:
+				return ((Long)this.value).doubleValue();
+			case TIMESTAMP:
+				return ((Timestamp)this.value).doubleValue();
+			case REAL:
+				return ((Double)this.value).doubleValue();
+			case STRING:
+				return Double.parseDouble((String)this.value);
+			case DATE:
+				return ((Date)this.value).getTime();
+			case BOOLEAN:
+				return ((Boolean)this.value).booleanValue() ? 1. : 0.;
+			case COLOR:
+				return ((Color)this.value).getRGB();
+			case OBJECT:
+				if (this.value instanceof Number)
+					return ((Number)this.value).doubleValue();
+				break;
+			case ENUMERATION:
+				if (this.value instanceof Enum<?>)
+					return ((Enum<?>)this.value).ordinal();
+				break;
+			case IMAGE:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case TYPE:
+			default:
+				throw new InvalidAttributeTypeException();
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(NumberFormatException _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setReal(double value) {
+		this.value = new Double(value);
+		this.type = AttributeType.REAL;
+		this.assigned = true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public String getString() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case STRING:
+				return (String)this.value;
+			case BOOLEAN:
+				return ((Boolean)this.value).toString();
+			case COLOR:
+			{
+				Color col = ((Color)this.value);
+				return Integer.toString(col.getRed())
+					+';'+col.getGreen()
+					+';'+col.getBlue()
+					+';'+col.getAlpha();
+			}
+			case UUID:
+			{
+				UUID uuid = ((UUID)this.value);
+				return uuid.toString();
+			}
+			case URL:
+			{
+				URL url = ((URL)this.value);
+				return url.toExternalForm();
+			}
+			case URI:
+			{
+				URI uri = ((URI)this.value);
+				return uri.toASCIIString();
+			}
+			case TIMESTAMP:
+			{
+				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$
+				return format.format(new Date(((Timestamp)this.value).longValue()));
+			}
+			case INTEGER:
+				return ((Long)this.value).toString();
+			case REAL:
+				return ((Double)this.value).toString();
+			case POINT:
+				Point2D pt2 = ((Point2D)this.value);
+				StringBuilder buffer = new StringBuilder();
+				buffer.append(pt2.getX());
+				buffer.append(";"); //$NON-NLS-1$
+				buffer.append(pt2.getY());
+				return buffer.toString();
+			case POINT3D:
+				Point3D pt3 = ((Point3D)this.value);
+				buffer = new StringBuilder();
+				buffer.append(pt3.getX());
+				buffer.append(";"); //$NON-NLS-1$
+				buffer.append(pt3.getY());
+				buffer.append(";"); //$NON-NLS-1$
+				buffer.append(pt3.getZ());
+				return buffer.toString();
+			case DATE:
+			{
+				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
+				return format.format((Date)this.value);
+			}
+			case POLYLINE:
+			{ 
+				buffer = new StringBuilder();
+				Point2D[] lstpt2 = ((Point2D[])this.value);
+				for(int i=0; i<lstpt2.length; ++i) {
+					if (lstpt2[i]!=null) {
+						if (buffer.length()>0) buffer.append(";"); //$NON-NLS-1$
+						buffer.append(lstpt2[i].getX());
+						buffer.append(";"); //$NON-NLS-1$
+						buffer.append(lstpt2[i].getY());
+					}
+				}
+				return buffer.toString();
+			}
+			case POLYLINE3D:
+			{ 
+				buffer = new StringBuilder();
+				Point3D[] lstpt3 = ((Point3D[])this.value);
+				for(int i=0; i<lstpt3.length; ++i) {
+					if (lstpt3[i]!=null) {
+						if (buffer.length()>0) buffer.append(";"); //$NON-NLS-1$
+						buffer.append(lstpt3[i].getX());
+						buffer.append(";"); //$NON-NLS-1$
+						buffer.append(lstpt3[i].getY());
+						buffer.append(";"); //$NON-NLS-1$
+						buffer.append(lstpt3[i].getZ());
+					}
+				}
+				return buffer.toString();
+			}
+			case ENUMERATION:
+			{
+				StringBuilder b = new StringBuilder();
+				Enum<?> enumeration = (Enum<?>)this.value;
+				Class<?> enumerationType = enumeration.getDeclaringClass();
+				String typeName = enumerationType.getCanonicalName();
+				b.append(typeName);
+				b.append("."); //$NON-NLS-1$
+				b.append(((Enum<?>)this.value).name());
+				return b.toString();
+			}
+			case TYPE:
+			{
+				return ((Class<?>)this.value).getCanonicalName();
+			}
+			case INET_ADDRESS:
+			case OBJECT:
+			case IMAGE:
+				return this.value.toString();
+			default:
+				throw new InvalidAttributeTypeException();
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();
+	}
+		
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setString(String value) {
+		this.value = value;
+		this.type = AttributeType.STRING;
+		this.assigned = this.value!=null;
+	}
+	
+	/** Parse a date according to the specified locale.
+	 */
+	private static Date extractDate(String text, Locale locale) {
+		DateFormat fmt;
+		for(int style=0; style<=3; ++style) {
+			// Date and time parsing
+			for(int style2=0; style2<=3; ++style2) {
+				fmt = DateFormat.getDateTimeInstance(style,style2,locale);
+				try {
+					return fmt.parse(text);
+				}
+				catch(ParseException _) {
+					//
+				}
+			}
+			// Date only parsing
+			fmt = DateFormat.getDateInstance(style,locale);
+			try {
+				return fmt.parse(text);
+			}
+			catch(ParseException _) {
+				//
+			}
+			// Time only parsing
+			fmt = DateFormat.getTimeInstance(style,locale);
+			try {
+				return fmt.parse(text);
+			}
+			catch(ParseException _) {
+				//
+			}
+		}
+		return null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Date getDate() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case DATE:
+				return (Date)((Date)this.value).clone();
+			case REAL:
+				 return new Date(((Double)this.value).longValue());				
+			case INTEGER:
+				 return new Date(((Long)this.value).longValue());				
+			case TIMESTAMP:
+				 return new Date(((Timestamp)this.value).longValue());				
+			case STRING:
+				String txt = (String)this.value;
+				DateFormat fmt;
+				Date dt;
+				
+				dt = extractDate(txt, Locale.getDefault());
+				if (dt!=null) return dt;
+				
+				dt = extractDate(txt, Locale.US);
+				if (dt!=null) return dt;
+				
+				dt = extractDate(txt, Locale.UK);
+				if (dt!=null) return dt;
+
+				try {
+					fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$
+					return fmt.parse(txt);
+				}
+				catch(ParseException _) {
+					//
+				}
+				fmt = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
+				return fmt.parse(txt);
+			case OBJECT:
+				if (this.value instanceof Date)
+					return (Date)this.value;
+				if (this.value instanceof Calendar)
+					return ((Calendar)this.value).getTime();
+				if (this.value instanceof Number)
+					return new Date(((Number)this.value).longValue());
+				break;
+			case BOOLEAN:
+			case COLOR:
+			case IMAGE:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(Exception e) {
+			//
+		}
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setDate(Date value) {
+		this.value = value;
+		this.type = AttributeType.DATE;
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean getBoolean() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case BOOLEAN:
+				return ((Boolean)this.value).booleanValue();
+			case STRING:
+				// Do not use the function Boolean.parseBoolean() because
+				// it replies false when the string does not contains "true"
+				if (TRUE_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return true;
+				if (YES_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return true;
+				if (OUI_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return true;
+				if (T_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return true;
+				if (Y_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return true;
+				if (O_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return true;
+
+				if (FALSE_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return false;
+				if (NO_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return false;
+				if (NON_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return false;
+				if (F_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return false;
+				if (N_CONSTANT.compareToIgnoreCase((String)this.value)==0)
+					return false;
+
+				break;
+			case INTEGER:
+				return ((Long)this.value).longValue() != 0;
+			case TIMESTAMP:
+				return ((Timestamp)this.value).longValue() != 0;
+			case REAL:
+				return ((Double)this.value).doubleValue() != 0.;
+			case OBJECT:
+				if (this.value instanceof Boolean)
+					return ((Boolean)this.value).booleanValue();
+				break;
+			case COLOR:
+			case DATE:
+			case IMAGE:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}			
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setBoolean(boolean value) {
+		this.value = new Boolean(value);
+		this.type = AttributeType.BOOLEAN;
+		this.assigned = true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean isObjectValue() {
+		return !isBaseType();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	@SuppressWarnings("unchecked")
+	public <T> T getJavaObject() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		if (!isObjectValue())
+			throw new InvalidAttributeTypeException();
+		if (isNotAssignedOrNull()) return null;
+		try {
+			return (T)this.value;
+		}
+		catch(ClassCastException _) {
+			throw new InvalidAttributeTypeException();
+		}			
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setJavaObject(Object value) {
+		this.value = value;
+		this.type = AttributeType.OBJECT;
+		this.assigned = true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public long getTimestamp() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case INTEGER:
+				return ((Long)this.value).longValue();
+			case TIMESTAMP:
+				return ((Timestamp)this.value).longValue();
+			case REAL:
+				return ((Double)this.value).longValue();
+			case STRING:
+				return Long.parseLong((String)this.value);
+			case DATE:
+				return ((Date)this.value).getTime();
+			case BOOLEAN:
+				return ((Boolean)this.value).booleanValue() ? 1 : 0;
+			case COLOR:
+				return ((Color)this.value).getRGB();
+			case OBJECT:
+				if (this.value instanceof Number)
+					return ((Number)this.value).longValue();
+				if (this.value instanceof Date)
+					return ((Date)this.value).getTime();
+				if (this.value instanceof Calendar)
+					return ((Calendar)this.value).getTimeInMillis();
+				break;
+			case IMAGE:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(NumberFormatException _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setTimestamp(long value) {
+		this.value = new Timestamp(value);
+		this.type = AttributeType.TIMESTAMP;
+		this.assigned = true;
+	}
+	
+	private static Point3D parsePoint3D(String text, boolean isStrict) {
+		String[] comp = text.split(";"); //$NON-NLS-1$
+		if (isStrict && comp.length!=3) {
+			return null;
+		}
+		Point3f pt3 = new Point3f();
+		if (comp.length>0) pt3.setX(Float.parseFloat(comp[0]));
+		if (comp.length>1) pt3.setY(Float.parseFloat(comp[1]));
+		if (comp.length>2) pt3.setZ(Float.parseFloat(comp[2]));
+		return pt3;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Point3D getPoint3D() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case COLOR:
+				Color col = (Color)this.value;
+				return new Point3f(col.getRed(),col.getGreen(),col.getBlue()); 
+			case REAL:
+				Double flt = (Double)this.value;
+				return new Point3f(flt.floatValue(),0,0); 
+			case INTEGER:
+				Long lg = (Long)this.value;
+				return new Point3f(lg.floatValue(),0,0); 
+			case TIMESTAMP:
+				Timestamp ts = (Timestamp)this.value;
+				return new Point3f(ts.floatValue(),0,0); 
+			case DATE:
+				Date dt = (Date)this.value;
+				return new Point3f(dt.getTime(),0,0); 
+			case POINT:
+				Point2D pt2 = (Point2D)this.value;
+				return new Point3f(pt2.getX(), pt2.getY(),0); 
+			case POINT3D:
+				return ((Point3D)this.value).clone(); 
+			case STRING:
+				return parsePoint3D((String)this.value, false);
+			case OBJECT:
+				if (this.value instanceof Tuple3D) {
+					Tuple3D<?> t3 = (Tuple3D<?>)this.value;
+					return new Point3f(t3.getX(), t3.getY(), t3.getZ()); 
+				}
+				if (this.value instanceof Tuple2D) {
+					Tuple2D<?> t2 = (Tuple2D<?>)this.value;
+					return new Point3f(t2.getX(), t2.getY(), 0); 
+				}
+				break;
+			case BOOLEAN:
+			case IMAGE:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(NumberFormatException _) {
+			//
+		}			
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setPoint3D(Point3D value) {
+		this.value = value;
+		this.type = AttributeType.POINT3D;
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setPoint3D(float x, float y, float z) {
+		this.value = new Point3f(x,y,z);
+		this.type = AttributeType.POINT3D;
+		this.assigned = true;
+	}
+	
+	private static Point2D parsePoint(String text, boolean isStrict) {
+		String[] comp = text.split(";"); //$NON-NLS-1$
+		if (isStrict && comp.length!=2) {
+			return null;
+		}
+		float x=0,y=0;
+		if (comp.length>0) x = Float.parseFloat(comp[0]);
+		if (comp.length>1) y = Float.parseFloat(comp[1]);
+		return new Point2f(x,y);
+		
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Point2D getPoint() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case COLOR:
+				Color col = (Color)this.value;
+				return new Point2f(col.getRed(),col.getGreen()); 
+			case REAL:
+				Double flt = (Double)this.value;
+				return new Point2f(flt.floatValue(),0f); 
+			case INTEGER:
+				Long lg = (Long)this.value;
+				return new Point2f(lg.floatValue(),0f); 
+			case TIMESTAMP:
+				Timestamp ts = (Timestamp)this.value;
+				return new Point2f(ts.floatValue(),0f); 
+			case DATE:
+				Date dt = (Date)this.value;
+				return new Point2f(dt.getTime(),0f); 
+			case POINT:
+				return new Point2f(((Point2D)this.value).getX(),
+						((Point2D)this.value).getY());
+			case POINT3D:
+				Point3D pt3 = (Point3D)this.value;
+				return new Point2f(pt3.getX(),pt3.getY()); 
+			case STRING:
+				return parsePoint((String)this.value, false);
+			case OBJECT:
+				if (this.value instanceof Tuple3D) {
+					Tuple3D<?> t3 = (Tuple3D<?>)this.value;
+					return new Point2f(t3.getX(), t3.getY()); 
+				}
+				if (this.value instanceof Tuple2D) {
+					Tuple2D<?> t2 = (Tuple2D<?>)this.value;
+					return new Point2f(t2.getX(), t2.getY()); 
+				}
+				break;
+			case BOOLEAN:
+			case IMAGE:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}			
+		catch(NumberFormatException _) {
+			//
+		}			
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setPoint(Point2D value) {
+		this.value = value;
+		this.type = AttributeType.POINT;
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setPoint(float x, float y) {
+		this.value = new Point2f(x,y);
+		this.type = AttributeType.POINT;
+		this.assigned = true;
+	}
+	
+	private static Color parseColor(String text, boolean isStrict) {
+		String[] comp = text.split(";"); //$NON-NLS-1$
+		if (isStrict && comp.length!=3 && comp.length!=4) {
+			return null;
+		}
+		int r=0,g=0,b=0,a=255;
+		if (comp.length>0) r = Integer.parseInt(comp[0]);
+		if (comp.length>1) g = Integer.parseInt(comp[1]);
+		if (comp.length>2) b = Integer.parseInt(comp[2]);
+		if (comp.length>3) a = Integer.parseInt(comp[3]);
+		if ((r<256)&&(r>=0)&&(g<256)&&(g>=0)&&(b<256)&&(b>=0)&&
+			(a<256)&&(a>=0))
+			return VectorToolkit.color(r,g,b,a);
+		return null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Color getColor() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case COLOR:
+				Color col = (Color)this.value;
+				return VectorToolkit.color(col.getRed(),col.getGreen(),col.getBlue(),col.getAlpha());
+			case POINT:
+				Point2D pt2 = (Point2D)this.value;
+				return VectorToolkit.color(pt2.getX(),pt2.getY(),0f, 1f);
+			case POINT3D:
+				Point3D pt3 = (Point3D)this.value;
+				return VectorToolkit.color(pt3.getX(),pt3.getY(),pt3.getZ(), 1f);
+			case STRING:
+				Color color = parseColor((String)this.value, false);
+				if (color!=null) return color;
+				break;
+			case INTEGER:
+				return VectorToolkit.color(((Long)this.value).intValue());
+			case TIMESTAMP:
+				return VectorToolkit.color(((Timestamp)this.value).intValue());
+			case REAL:
+				return VectorToolkit.color(((Double)this.value).intValue());
+			case DATE:
+				return VectorToolkit.color((int)((Date)this.value).getTime());
+			case OBJECT:
+				if (this.value instanceof Color)
+					return (Color)this.value;
+				if (this.value instanceof Number)
+					return VectorToolkit.color(((Number)this.value).intValue());
+				if (this.value instanceof Date)
+					return VectorToolkit.color((int)((Date)this.value).getTime());
+				if (this.value instanceof Calendar)
+					return VectorToolkit.color((int)((Calendar)this.value).getTimeInMillis());
+				break;
+			case BOOLEAN:
+			case IMAGE:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(NumberFormatException _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();		
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setColor(Color c) {
+		this.value = c;
+		this.type = AttributeType.COLOR;		
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setColor(float r, float g, float b) {
+		this.value = VectorToolkit.color(r,g,b, 1f);
+		this.type = AttributeType.COLOR;				
+		this.assigned = true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setColor(float r, float g, float b, float a) {
+		this.value = VectorToolkit.color(r,g,b,a);
+		this.type = AttributeType.COLOR;				
+		this.assigned = true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setColor(int r, int g, int b) {
+		this.value = VectorToolkit.color(r,g,b,255);
+		this.type = AttributeType.COLOR;				
+		this.assigned = true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setColor(int r, int g, int b, int a) {
+		this.value = VectorToolkit.color(r,g,b,a);
+		this.type = AttributeType.COLOR;				
+		this.assigned = true;
+	}
+
+	private static UUID parseUUID(String text) {
+		try {
+			URI uri = new URI(text);
+			if ("uuid".equalsIgnoreCase(uri.getScheme())) { //$NON-NLS-1$
+				return UUID.fromString(uri.getHost());
+			}
+		}
+		catch(Throwable _) {
+			//
+		}
+		try {
+			return UUID.fromString(text);
+		}
+		catch(Throwable _) {
+			//
+		}
+		return null;
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public UUID getUUID() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case UUID:
+				UUID id = (UUID)this.value;
+				return new UUID(id.getMostSignificantBits(), id.getLeastSignificantBits());
+			case URI:
+				URI uri = (URI)this.value;
+				if ("uuid".equalsIgnoreCase(uri.getScheme())) { //$NON-NLS-1$
+					try {
+						return UUID.fromString(uri.getHost());
+					}
+					catch(AssertionError e) {
+						throw e;
+					}
+					catch(Throwable _) {
+						//
+					}
+				}
+				break; // see below for the other cases
+			case OBJECT:
+				if (this.value instanceof UUID) {
+					return (UUID)this.value;
+				}
+				if (this.value instanceof URI
+					&& "uuid".equalsIgnoreCase(((URI)this.value).getScheme())) { //$NON-NLS-1$
+					try {
+						return UUID.fromString(((URI)this.value).getHost());
+					}
+					catch(AssertionError e) {
+						throw e;
+					}
+					catch(Throwable _) {
+						//
+					}
+				}
+				break; // see below for the other cases
+			case STRING:
+			case BOOLEAN:
+			case COLOR:
+			case DATE:
+			case IMAGE:
+			case INTEGER:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case REAL:
+			case TIMESTAMP:
+			case URL:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+				break; // see below, for the computation of an UUID from the value
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(NumberFormatException _) {
+			//
+		}
+		if (this.value==null)
+			return (UUID)AttributeType.UUID.getDefaultValue();
+		String s = this.value.toString();
+		if (s==null || "".equals(s)) //$NON-NLS-1$
+			return (UUID)AttributeType.UUID.getDefaultValue();
+		try {
+			return UUID.fromString(s);
+		}
+		catch(AssertionError e) {
+			throw e;
+		}
+		catch(Throwable _) {
+			//
+		}
+		return UUID.nameUUIDFromBytes(s.getBytes());
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public URL getURL() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case URL:
+				return new URL(((URL)this.value).toExternalForm());
+			case URI:
+				return ((URI)this.value).toURL();
+			case STRING:
+				return new URL((String)this.value);
+			case OBJECT:
+				if (this.value instanceof URL)
+					return (URL)this.value;
+				if (this.value instanceof URI)
+					return ((URI)this.value).toURL();
+				break; // Other objects, see below
+			case INET_ADDRESS:
+				return new URL(DEFAULT_SCHEME.name(), ((InetAddress)this.value).getHostAddress(), ""); //$NON-NLS-1$
+			case UUID:
+			case BOOLEAN:
+			case COLOR:
+			case DATE:
+			case IMAGE:
+			case INTEGER:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case REAL:
+			case TIMESTAMP:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(MalformedURLException _) {
+			//
+		}
+		if (this.value==null)
+			return (URL)AttributeType.URL.getDefaultValue();
+		String s = this.value.toString();
+		if (s==null)
+			return (URL)AttributeType.URL.getDefaultValue();
+		try {
+			return new URL(s);
+		}
+		catch (MalformedURLException _) {
+			throw new InvalidAttributeTypeException();
+		}
+	}
+	
+	private static URI parseURI(String text) {
+		try {
+			URI uri = new URI(text);
+			if (uri.getScheme()!=null && !uri.getScheme().isEmpty())
+				return uri;
+		}
+		catch(Throwable _) {
+			//
+		}
+		return null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public URI getURI() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case URL:
+				return ((URL)this.value).toURI();
+			case URI:
+				return new URI(((URI)this.value).toASCIIString());
+			case STRING:
+				return new URI((String)this.value);
+			case UUID:
+				return new URI("uuid:"+((UUID)this.value).toString()); //$NON-NLS-1$
+			case OBJECT:
+				if (this.value instanceof URI)
+					return (URI)this.value;
+				if (this.value instanceof URL)
+					return ((URL)this.value).toURI();
+				if (this.value instanceof UUID)
+					return new URI("uuid:"+((UUID)this.value).toString()); //$NON-NLS-1$
+				break; // Other objects, see below
+			case INET_ADDRESS:
+				return new URI(DEFAULT_SCHEME.name(), ((InetAddress)this.value).getHostAddress(), ""); //$NON-NLS-1$
+			case BOOLEAN:
+			case COLOR:
+			case DATE:
+			case IMAGE:
+			case INTEGER:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case REAL:
+			case TIMESTAMP:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(URISyntaxException _) {
+			//
+		}
+		if (this.value==null)
+			return (URI)AttributeType.URI.getDefaultValue();
+		String s = this.value.toString();
+		if (s==null)
+			return (URI)AttributeType.URI.getDefaultValue();
+		try {
+			return new URI(s);
+		}
+		catch (URISyntaxException _) {
+			throw new InvalidAttributeTypeException();
+		}
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setUUID(UUID u) {
+		this.value = (u==null) ? AttributeType.UUID.getDefaultValue() : u;
+		this.type = AttributeType.UUID;		
+		this.assigned = this.value!=null;
+	}
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param id
+	 */
+	public void setUUID(String id) {
+		try {
+			this.value = (id!=null) ? UUID.fromString(id) : null;
+		}
+		catch(Throwable _) {
+			assert(id!=null);
+			this.value = UUID.nameUUIDFromBytes(id.getBytes());
+		}
+		this.type = AttributeType.UUID;				
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setURL(URL u) {
+		this.value = (u==null) ? AttributeType.URL.getDefaultValue() : u;
+		this.type = AttributeType.URL;		
+		this.assigned = this.value!=null;
+	}
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param url
+	 */
+	public void setURL(String url) {
+		try {
+			this.value = (url!=null) ? new URL(url) : null;
+		}
+		catch(Throwable _) {
+			this.value = null;
+		}
+		this.type = AttributeType.URL;				
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setURI(URI u) {
+		this.value = (u==null) ? AttributeType.URI.getDefaultValue() : u;
+		this.type = AttributeType.URI;		
+		this.assigned = this.value!=null;
+	}
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param uri
+	 */
+	public void setURI(String uri) {
+		try {
+			this.value = (uri!=null) ? new URI(uri) : null;
+		}
+		catch(Throwable _) {
+			this.value = null;
+		}
+		this.type = AttributeType.URI;				
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Image getImage() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssigned();
+			switch(this.type) {
+			case IMAGE:
+				assertAssignedAndNotNull();
+				return (Image)this.value;
+			case OBJECT:
+				if ((this.value==null)||(this.value instanceof Image)) return (Image)this.value;
+				break;
+			case BOOLEAN:
+			case COLOR:
+			case DATE:
+			case INTEGER:
+			case POINT:
+			case POINT3D:
+			case POLYLINE:
+			case POLYLINE3D:
+			case REAL:
+			case STRING:
+			case TIMESTAMP:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();		
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setImage(Image c) {
+		this.value = c;
+		this.type = AttributeType.IMAGE;		
+		this.assigned = true;
+	}
+
+	private static Point3D[] parsePolyline3D(String text, boolean isStrict) {
+		String[] comp = text.split(";"); //$NON-NLS-1$
+		if (isStrict && (comp.length%3)!=0) {
+			return null;
+		}
+		int fullPoints = comp.length/3;
+		boolean addPt = (fullPoints*3!=comp.length); 
+		Point3D[] tab = new Point3D[addPt ? fullPoints+1 : fullPoints];
+		for(int i=2,j=0; (i<comp.length)&&(j<tab.length); i+=3,++j) {
+			tab[j] = new Point3f(
+					Float.parseFloat(comp[i-2]),
+					Float.parseFloat(comp[i-1]),
+					Float.parseFloat(comp[i]));
+		}
+		if (addPt) {
+			float x = Float.parseFloat(comp[fullPoints*3]);
+			int idx = fullPoints*3+1;
+			float y = idx<comp.length ? Float.parseFloat(comp[idx]) : 0;
+			tab[tab.length-1]  = new Point3f(x, y, 0);
+		}
+		return tab;
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Point3D[] getPolyline3D() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case POINT:
+				Point2D pt2 = (Point2D)this.value;
+				return new Point3D[] {
+						new Point3f(pt2.getX(),pt2.getY(),0f) 
+				};
+			case POINT3D:
+				return new Point3D[] {
+					((Point3D)this.value).clone() 
+				};
+			case POLYLINE:
+			{
+				Point2D[] current = (Point2D[])this.value;
+				Point3D[] tab = new Point3D[current.length];
+				for(int i=0; i<current.length; ++i) {
+					tab[i] = new Point3f(
+								current[i].getX(),
+								current[i].getY(),
+								0f); 
+				}
+				return tab;
+			}
+			case POLYLINE3D:
+				return (Point3D[])this.value;
+			case STRING:
+				return parsePolyline3D((String)this.value, false);
+			case OBJECT:
+				if (this.value instanceof Tuple2D<?>) {
+					Tuple2D<?> t2 = (Tuple2D<?>)this.value;
+					return new Point3D[] {
+						new Point3f(t2.getX(),t2.getY(),0) 
+					};
+				}
+				else if (this.value instanceof Tuple3D<?>) {
+					Tuple3D<?> t2 = (Tuple3D<?>)this.value;
+					return new Point3D[] {
+							new Point3f(t2.getX(), t2.getY(), t2.getZ())
+					};
+				}
+				else if (this.value.getClass().isArray()) {
+					Class<?> elementType = this.value.getClass().getComponentType();
+					if (Point3D.class.equals(elementType)) {
+						return (Point3D[])this.value;
+					}
+					int size = Array.getLength(this.value);
+					if (Tuple3D.class.isAssignableFrom(elementType)) {
+						Point3D[] pa3 = new Point3D[size];
+						for(int i=0; i<pa3.length; ++i) {
+							Tuple3D<?> t = (Tuple3D<?>)Array.get(this.value, i);
+							pa3[i] = new Point3f(t);
+						}
+						return pa3;
+					}
+					if (Tuple2D.class.isAssignableFrom(elementType)) {
+						Point3D[] pa3 = new Point3D[size];
+						for(int i=0; i<pa3.length; ++i) {
+							Tuple2D<?> t = (Tuple2D<?>)Array.get(this.value, i);
+							pa3[i] = new Point3f(t.getX(), t.getY(), 0);
+						}
+						return pa3;
+					}
+				}
+				break;
+			case BOOLEAN:
+			case COLOR:
+			case DATE:
+			case IMAGE:
+			case INTEGER:
+			case REAL:
+			case TIMESTAMP:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(NumberFormatException _) {
+			//
+		}			
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setPolyline3D(Point3D... value) {
+		this.value = value;
+		this.type = AttributeType.POLYLINE3D;
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setPolyline3D(Collection<? extends Point3D> value) {
+		if (value==null) {
+			this.value = null;
+		}
+		else {
+			Point3D[] tab = new Point3D[value.size()];
+			value.toArray(tab);
+			this.value = tab;
+		}
+		this.type = AttributeType.POLYLINE3D;
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void addToPolyline3D(Point3D... p) {
+		Point3D[] tab;
+		if (this.value instanceof Point3D[]) {
+			int size = ((Point3D[])this.value).length;
+			tab = new Point3D[size+p.length];
+			System.arraycopy(this.value,0,tab,0,size);
+			System.arraycopy(p,0,tab,size,p.length);
+		}
+		else {
+			tab = p;
+		}
+		this.value = tab;
+		this.assigned = this.value!=null;
+		this.type = AttributeType.POLYLINE3D;		
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void addToPolyline3D(Collection<? extends Point3D> p) {
+		Point3D[] tab;
+		if (this.value instanceof Point3D[]) {
+			int size = ((Point3D[])this.value).length;
+			tab = new Point3D[size+p.size()];
+			System.arraycopy(this.value,0,tab,0,size);
+			System.arraycopy(p.toArray(),0,tab,size,p.size());
+		}
+		else {
+			tab = new Point3D[p.size()];
+			p.toArray(tab);
+		}
+		this.value = tab;
+		this.assigned = this.value!=null;
+		this.type = AttributeType.POLYLINE3D;		
+	}
+
+	private static Point2D[] parsePolyline(String text, boolean isStrict) {
+		String[] comp = text.split(";"); //$NON-NLS-1$
+		if (isStrict && (comp.length%2)!=0) {
+			return null;
+		}
+		int fullPoints = comp.length/2;
+		boolean addPt = (fullPoints*2!=comp.length); 
+		Point2D[] tab = new Point2D[addPt ? fullPoints+1 : fullPoints];
+		for(int i=1,j=0; (i<comp.length)&&(j<fullPoints); i+=2,++j) {
+			tab[j] = new Point2f(
+					Float.parseFloat(comp[i-1]),
+					Float.parseFloat(comp[i]));
+		}
+		if (addPt) {
+			tab[tab.length-1]  = new Point2f(
+					Float.parseFloat(comp[comp.length-1]),
+					0);
+		}
+		return tab;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Point2D[] getPolyline() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case POINT:
+				return new Point2D[] {
+						new Point2f(((Point2D)this.value).getX(),
+								((Point2D)this.value).getY())
+				};
+			case POINT3D:
+				Point3D pt3 = (Point3D)this.value;
+				return new Point2D[] {
+					new Point2f(pt3.getX(),pt3.getY()) 
+				};
+			case POLYLINE:
+				return (Point2D[])this.value;
+			case POLYLINE3D:
+			{
+				Point3D[] current = (Point3D[])this.value;
+				Point2D[] tab = new Point2D[current.length];
+				for(int i=0; i<current.length; ++i) {
+					tab[i] = new Point2f(
+								current[i].getX(),
+								current[i].getY()); 
+				}
+				return tab;
+			}
+			case STRING:
+				return parsePolyline((String)this.value, false);
+			case OBJECT:
+				if (this.value instanceof Tuple2D) {
+					return new Point2D[] {
+							new Point2f(((Tuple2D<?>)this.value).getX(),
+									((Tuple2D<?>)this.value).getY())
+					};
+				}
+				else if (this.value instanceof Tuple3D) {
+					Tuple3D<?> t3 = (Tuple3D<?>)this.value;
+					return new Point2D[] {
+						new Point2f(t3.getX(),t3.getY()) 
+					};
+				}
+				else if (this.value instanceof Point2D[]) {
+					return (Point2D[])this.value;
+				}
+				else if (this.value instanceof Tuple2D[]) {
+					Tuple2D<?>[] ta2 = (Tuple2D[])this.value;
+					Point2D[] pa2 = new Point2D[ta2.length];
+					for(int i=0; i<pa2.length; ++i) pa2[i] = new Point2f(ta2[i]);
+				}
+				else if (this.value instanceof Tuple3D[]) {
+					Tuple3D<?>[] ta3 = (Tuple3D[])this.value;
+					Point2D[] pa2 = new Point2D[ta3.length];
+					for(int i=0; i<pa2.length; ++i) pa2[i] = new Point2f(ta3[i].getX(), ta3[i].getY());
+				}
+				break;
+			case BOOLEAN:
+			case COLOR:
+			case DATE:
+			case IMAGE:
+			case INTEGER:
+			case REAL:
+			case TIMESTAMP:
+			case URI:
+			case URL:
+			case UUID:
+			case INET_ADDRESS:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(NumberFormatException _) {
+			//
+		}			
+		throw new InvalidAttributeTypeException();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setPolyline(Point2D... value) {
+		this.value = value;
+		this.type = AttributeType.POLYLINE;
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setPolyline(Collection<? extends Point2D> value) {
+		if (value==null) {
+			this.value = null;
+		}
+		else {
+			Point2D[] tab = new Point2D[value.size()];
+			value.toArray(tab);
+			this.value = tab;
+		}
+		this.value = value;
+		this.type = AttributeType.POLYLINE;
+		this.assigned = this.value!=null;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void addToPolyline(Point2D... p) {
+		Point2D[] tab;
+		if (this.value instanceof Point2D[]) {
+			int size = ((Point2D[])this.value).length;
+			tab = new Point2D[size+p.length];
+			System.arraycopy(this.value,0,tab,0,size);
+			System.arraycopy(this.value,0,tab,size,p.length);
+		}
+		else {
+			tab = p;
+		}
+		this.value = tab;
+		this.assigned = this.value!=null;
+		this.type = AttributeType.POLYLINE;		
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void addToPolyline(Collection<? extends Point2D> p) {
+		Point2D[] tab;
+		if (this.value instanceof Point2D[]) {
+			int size = ((Point2D[])this.value).length;
+			tab = new Point2D[size+p.size()];
+			System.arraycopy(this.value,0,tab,0,size);
+			System.arraycopy(this.value,0,tab,size,p.size());
+		}
+		else {
+			tab = new Point2D[p.size()];
+			p.toArray(tab);
+		}
+		this.value = tab;
+		this.assigned = this.value!=null;
+		this.type = AttributeType.POLYLINE;		
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public InetAddress getInetAddress() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case INET_ADDRESS:
+				return (InetAddress)this.value;
+			case STRING:
+				try {
+					InetAddress adr = InetAddress.getByName(this.value.toString());
+					if (adr!=null) return adr;
+				}
+				catch(Throwable _) {
+					//
+				}
+				break;
+			case OBJECT:
+				if (this.value instanceof InetAddress)
+					return (InetAddress)this.value;
+				if (this.value instanceof InetSocketAddress)
+					return ((InetSocketAddress)this.value).getAddress();
+				if (this.value!=null) {
+					InetAddress adr;
+					try {
+						adr = InetAddress.getByName(this.value.toString());
+						if (adr!=null) return adr;
+					}
+					catch(Throwable _) {
+						//
+					}
+				}
+				else {
+					return null;
+				}
+				break;
+			case URI:
+				URI uri = (URI)this.value;
+				return InetAddress.getByName(uri.getHost());
+			case URL:
+				URL url = (URL)this.value;
+				return InetAddress.getByName(url.getHost());
+			case COLOR:
+			case POINT:
+			case POINT3D:
+			case INTEGER:
+			case TIMESTAMP:
+			case REAL:
+			case DATE:
+			case BOOLEAN:
+			case IMAGE:
+			case POLYLINE:
+			case POLYLINE3D:
+			case UUID:
+			case ENUMERATION:
+			case TYPE:
+			default:
+			}
+		}
+		catch(ClassCastException _) {
+			//
+		}
+		catch(NumberFormatException _) {
+			//
+		}
+		catch (UnknownHostException e) {
+			//
+		}
+		throw new InvalidAttributeTypeException();		
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void setInetAddress(InetAddress a) {
+		this.value = a;
+		this.type = AttributeType.INET_ADDRESS;		
+		this.assigned = this.value!=null;
+	}
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param a
+	 */
+	public void setInetAddress(InetSocketAddress a) {
+		this.value = a.getAddress();
+		this.type = AttributeType.INET_ADDRESS;				
+		this.assigned = this.value!=null;
+	}
+
+	/**
+	 * Set the value of this metadata.
+	 * 
+	 * @param hostname
+	 */
+	public void setInetAddress(String hostname) {
+		this.type = AttributeType.INET_ADDRESS;				
+		try {
+			this.value = InetAddress.getByName(hostname);
+		}
+		catch(Throwable _) {
+			this.value = null;
+		}
+		this.assigned = this.value!=null;
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public Enum<?> getEnumeration() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		if (this.value==null) return null;
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case ENUMERATION:
+				return (Enum<?>)this.value;
+			case STRING:
+				int index = ((String)this.value).lastIndexOf('.');
+				if (index>=0) {
+					String classname = ((String)this.value).substring(0, index);
+					String enumName = ((String)this.value).substring(index+1);
+					Class classType = Class.forName(classname);
+					if (Enum.class.isAssignableFrom(classType)) {
+						return Enum.valueOf(classType, enumName);
+					}
+				}
+				break;
+			case OBJECT:
+				if (this.value instanceof Enum<?>)
+					return (Enum<?>)this.value;
+				
+				break;
+			case REAL:
+			case INTEGER:
+				break;
+			case INET_ADDRESS:
+			case COLOR:
+			case POINT:
+			case POINT3D:
+			case TIMESTAMP:
+			case DATE:
+			case BOOLEAN:
+			case IMAGE:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case TYPE:
+			default:
+			}
+		}
+		catch(Throwable _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();		
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public <T extends Enum<T>> T getEnumeration(Class<T> type) throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		if (this.value==null) return null;
+		try {
+			assertAssignedAndNotNull();
+			switch(this.type) {
+			case ENUMERATION:
+				return type.cast(this.value);
+			case STRING:
+				int index = ((String)this.value).lastIndexOf('.');
+				if (index>=0) {
+					String classname = ((String)this.value).substring(0, index);
+					String enumName = ((String)this.value).substring(index+1);
+					Class<?> classType = Class.forName(classname);
+					assert(type.equals(classType));
+					return Enum.valueOf(type, enumName);
+				}
+				break;
+			case OBJECT:
+				if (this.value instanceof Enum<?>)
+					return type.cast(this.value);
+				
+				break;
+			case REAL:
+			case INTEGER:
+				break;
+			case INET_ADDRESS:
+			case COLOR:
+			case POINT:
+			case POINT3D:
+			case TIMESTAMP:
+			case DATE:
+			case BOOLEAN:
+			case IMAGE:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			case TYPE:
+			default:
+			}
+		}
+		catch(Throwable _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();		
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setEnumeration(Enum<?> e) {
+		this.value = e;
+		this.type = AttributeType.ENUMERATION;		
+		this.assigned = this.value!=null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Class<?> getJavaClass() throws InvalidAttributeTypeException, AttributeNotInitializedException {
+		assertAssignedAndNotNull();
+		try {
+			switch(this.type) {
+			case TYPE:
+			case OBJECT:
+				return (Class<?>)this.value;
+			case STRING:
+				return Class.forName((String)this.value);
+			case ENUMERATION:
+			case REAL:
+			case INTEGER:
+			case INET_ADDRESS:
+			case COLOR:
+			case POINT:
+			case POINT3D:
+			case TIMESTAMP:
+			case DATE:
+			case BOOLEAN:
+			case IMAGE:
+			case POLYLINE:
+			case POLYLINE3D:
+			case URI:
+			case URL:
+			case UUID:
+			default:
+			}
+		}
+		catch(Throwable _) {
+			//
+		}
+		throw new InvalidAttributeTypeException();		
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setJavaClass(Class<?> e) {
+		this.value = e;
+		this.type = AttributeType.TYPE;		
+		this.assigned = this.value!=null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean isAssigned() {
+		return this.assigned;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void uninitializeValue() {
+		this.value = null;
+		this.assigned = false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean flush() {
+		return true;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Comparator<? extends AttributeValue> valueComparator() {
+		return new AttributeValueComparator();
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/InvalidAttributeTypeException.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/InvalidAttributeTypeException.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/InvalidAttributeTypeException.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,52 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+
+/**
+ * This exception is generated each time the an invalid type
+ * was used for metadata.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class InvalidAttributeTypeException extends AttributeException {
+	
+	private static final long serialVersionUID = -4301702969671847467L;
+
+	/**
+	 */
+	public InvalidAttributeTypeException() {
+		//
+	}
+
+	/**
+	 * @param name is the name of the attribute for which the type was invalid.
+	 */
+	public InvalidAttributeTypeException(String name) {
+		super(name);
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/NullAttribute.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/NullAttribute.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/NullAttribute.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,99 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.io.Serializable;
+
+
+/**
+ * Class that is representing a <code>null</code> value
+ * for the embedded type of attribute.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public final class NullAttribute implements Serializable, Cloneable {
+
+	private static final long serialVersionUID = 259205366482306499L;
+	
+	private final AttributeType type;
+	
+	/**
+	 * @param type
+	 */
+	public NullAttribute(AttributeType type) {
+		this.type = type;
+	}
+
+	/** Replies the type.
+	 * 
+	 * @return the type.
+	 */
+	public AttributeType getType() {
+		return this.type;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public NullAttribute clone() {
+		try {
+			return (NullAttribute)super.clone();
+		}
+		catch (CloneNotSupportedException e) {
+			throw new Error(e);
+		}
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (obj==null) return true;
+		if (obj instanceof NullAttribute) {
+			return this.type==((NullAttribute)obj).type;
+		}
+		return false;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		return this.type.hashCode();
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		return "null"; //$NON-NLS-1$
+	}
+	
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/Timestamp.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/Timestamp.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/attr/Timestamp.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,109 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.text.MessageFormat;
+import java.util.Date;
+
+/**
+ * Container of timestamp.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+class Timestamp extends Number {
+
+	private static final long serialVersionUID = 499564400887069856L;
+	
+	private final long time;
+	
+	/**
+	 * @param time
+	 */
+	public Timestamp(long time) {
+		this.time = time;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public double doubleValue() {
+		return this.time;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public float floatValue() {
+		return this.time;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int intValue() {
+		return (int)this.time;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public long longValue() {
+		return this.time;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof Number) {
+			return this.time==((Number)obj).longValue();
+		}
+		return false;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		return Long.valueOf(this.time).hashCode();
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		return MessageFormat.format("{0,date,full} {0,time,full}", //$NON-NLS-1$
+				new Date(this.time));
+	}
+	
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractAttributeCollection.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractAttributeCollection.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractAttributeCollection.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,223 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.collection.AttributeChangeEvent.Type;
+
+/**
+ * This class implements an abstract object with attributes.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class AbstractAttributeCollection extends AbstractAttributeProvider implements AttributeCollection {
+	
+	private List<AttributeChangeListener> listenerList = null;
+	private boolean isEventFirable = true;
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public synchronized boolean isEventFirable() {
+		return this.isEventFirable;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public synchronized void setEventFirable(boolean isFirable) {
+		this.isEventFirable = isFirable;
+	}
+	
+	/** Make a deep copy of this object and replies the copy.
+	 * 
+	 * @return the deep copy.
+	 */
+	@Override
+	public AttributeCollection clone() {
+		AbstractAttributeCollection clone = (AbstractAttributeCollection)super.clone();
+		clone.listenerList = null;
+		return clone;
+	}
+
+	/** Fire the addition event.
+	 * 
+	 * @param name is the name of the attribute for which the event occured.
+	 * @param attr is the value of the attribute.
+	 */
+	protected synchronized void fireAttributeAddedEvent(String name, AttributeValue attr) {
+		if (this.listenerList!=null && isEventFirable()) {
+			AttributeChangeListener[] list = new AttributeChangeListener[this.listenerList.size()];
+			this.listenerList.toArray(list);
+			AttributeChangeEvent event = new AttributeChangeEvent(
+					this, 				//source
+					Type.ADDITION,		//type
+					null,				//old name
+					null,				//old value
+					name,				//current name
+					attr);				//current value
+			for(AttributeChangeListener listener : list) {
+				listener.onAttributeChangeEvent(event);
+			}
+		}
+	}
+
+	/** Fire the attribute change event.
+	 * 
+	 * @param name is the name of the attribute for which the event occured.
+	 * @param oldValue is the previous value of the attribute
+	 * @param currentValue is the current value of the attribute
+	 */
+	protected synchronized void fireAttributeChangedEvent(String name, AttributeValue oldValue, AttributeValue currentValue) {
+		if (this.listenerList!=null && isEventFirable()) {
+			AttributeChangeListener[] list = new AttributeChangeListener[this.listenerList.size()];
+			this.listenerList.toArray(list);
+			AttributeChangeEvent event = new AttributeChangeEvent(
+					this, 				//source
+					Type.VALUE_UPDATE,	//type
+					name,				//old name
+					oldValue,			//old value
+					name,				//current name
+					currentValue);		//current value
+			for(AttributeChangeListener listener : list) {
+				listener.onAttributeChangeEvent(event);
+			}
+		}
+	}
+
+	/** Fire the all attribute removal event.
+	 */
+	protected synchronized void fireAttributeClearedEvent() {
+		if (this.listenerList!=null && isEventFirable()) {
+			AttributeChangeListener[] list = new AttributeChangeListener[this.listenerList.size()];
+			this.listenerList.toArray(list);
+			AttributeChangeEvent event = new AttributeChangeEvent(
+					this, 				//source
+					Type.REMOVE_ALL,	//type
+					null,				//old name
+					null,				//old value
+					null,				//current name
+					null);				//current value
+			for(AttributeChangeListener listener : list) {
+				listener.onAttributeChangeEvent(event);
+			}
+		}
+	}
+
+	/** Fire the an attribute removal event.
+	 * 
+	 * @param name is the name of the attribute for which the event occured.
+	 * @param oldValue is the previous value of the attribute
+	 */
+	protected synchronized void fireAttributeRemovedEvent(String name, AttributeValue oldValue) {
+		if (this.listenerList!=null && isEventFirable()) {
+			AttributeChangeListener[] list = new AttributeChangeListener[this.listenerList.size()];
+			this.listenerList.toArray(list);
+			AttributeChangeEvent event = new AttributeChangeEvent(
+					this, 				//source
+					Type.REMOVAL,		//type
+					name,				//old name
+					oldValue,			//old value
+					name,				//current name
+					oldValue);			//current value
+			for(AttributeChangeListener listener : list) {
+				listener.onAttributeChangeEvent(event);
+			}
+		}
+	}
+
+	/** Fire the renaming event.
+	 * 
+	 * @param oldName is the previous name of the attribute (before renaming)
+	 * @param newName is the new name of the attribute (after renaming)
+	 * @param attr is the value of the attribute.
+	 */
+	protected synchronized void fireAttributeRenamedEvent(String oldName, String newName, AttributeValue attr) {
+		if (this.listenerList!=null && isEventFirable()) {
+			AttributeChangeListener[] list = new AttributeChangeListener[this.listenerList.size()];
+			this.listenerList.toArray(list);
+			AttributeChangeEvent event = new AttributeChangeEvent(
+					this, 				//source
+					Type.RENAME,		//type
+					oldName,			//old name
+					attr,				//old value
+					newName,			//current name
+					attr);				//current value
+			for(AttributeChangeListener listener : list) {
+				listener.onAttributeChangeEvent(event);
+			}
+		}
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public synchronized void addAttributeChangeListener(AttributeChangeListener listener) {
+		if (listener!=null) {
+			if (this.listenerList==null)
+				this.listenerList = new LinkedList<AttributeChangeListener>();
+			this.listenerList.add(listener);
+		}
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public synchronized void removeAttributeChangeListener(AttributeChangeListener listener) {
+		if (listener!=null) {
+			if (this.listenerList!=null) {
+				this.listenerList.remove(listener);
+				if (this.listenerList.isEmpty())
+					this.listenerList = null;
+			}
+		}
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public final boolean renameAttribute(String oldname, String newname) {
+		return renameAttribute(oldname, newname, false);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public final void copyFrom(AttributeProvider otherContainer) throws AttributeException {
+		for (Attribute attr : otherContainer.attributes()) {
+			setAttribute(attr);
+		}
+	}
+	
+}
+

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractAttributeProvider.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractAttributeProvider.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractAttributeProvider.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,529 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.NullAttribute;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+
+/**
+ * This class implements an abstract attribute provider.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class AbstractAttributeProvider implements AttributeProvider, Iterable<Attribute>, Cloneable {
+		
+	/** Ensure that the <code>null</code> value for <var>rawAttributeValue</var>
+	 * is catched and replaced by a dedicated representant object.
+	 * This function permits to keep the type of a value even if it is <code>null</code>.
+	 * 
+	 * @param rawAttributeValue is the value to protect.
+	 * @param type is the type of the attribute to preserve over time.
+	 * @return the value, or the representant of the java <code>null</code> value.
+	 * @see #unprotectNull(Object)
+	 */
+	protected static Object protectNull(Object rawAttributeValue, AttributeType type) {
+		if (rawAttributeValue==null) {
+			if (type.isNullAllowed())
+				return new NullAttribute(type);
+			throw new NullPointerException();
+		}
+		return rawAttributeValue;
+	}
+
+	/** Ensure that the <code>null</code> value for <var>rawAttributeValue</var>
+	 * is catched and the dedicated representant object for <code>null</code>
+	 * if replace by the real <code>null</code> java value.
+	 * 
+	 * @param rawAttributeValue is the value to protect.
+	 * @return the value.
+	 * @see #protectNull(Object, AttributeType)
+	 */
+	protected static Object unprotectNull(Object rawAttributeValue) {
+		if (rawAttributeValue instanceof NullAttribute)
+			return null;
+		return rawAttributeValue;
+	}
+
+	@Override
+	public final Map<String, Object> toMap() {
+		Map<String,Object> map = new TreeMap<String,Object>();
+		toMap(map);
+		return map;
+	}
+
+	/** Replies an iterator on the attributes.
+	 * 
+	 * @return {@inheritDoc}
+	 */
+	@Override
+	public Iterator<Attribute> iterator() {
+		return new AttributeIterator(this);
+	}
+	
+	/** Make a deep copy of this object and replies the copy.
+	 * 
+	 * @return the deep copy.
+	 */
+	@Override
+	public AttributeProvider clone() {
+		try {
+			return (AttributeProvider)super.clone();
+		}
+		catch(CloneNotSupportedException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Iterable<Attribute> attributes() {
+		return this;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean getAttributeAsBool(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getBoolean();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public int getAttributeAsInt(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return (int)value.getInteger();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public long getAttributeAsLong(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getInteger();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float getAttributeAsFloat(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return (float)value.getReal();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public double getAttributeAsDouble(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getReal();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public String getAttributeAsString(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getString();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public UUID getAttributeAsUUID(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getUUID();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public URL getAttributeAsURL(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getURL();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public URI getAttributeAsURI(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getURI();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Image getAttributeAsImage(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getImage();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Date getAttributeAsDate(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getDate();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Color getAttributeAsColor(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getColor();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public InetAddress getAttributeAsInetAddress(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getInetAddress();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Enum<?> getAttributeAsEnumeration(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getEnumeration();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public <T extends Enum<T>> T getAttributeAsEnumeration(String name, Class<T> type) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getEnumeration(type);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Class<?> getAttributeAsJavaClass(String name) throws AttributeException {
+		AttributeValue value = getAttribute(name);
+		if (value==null) throw new NoAttributeFoundException(name);
+		return value.getJavaClass();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean getAttribute(String name, boolean defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getBoolean();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public int getAttribute(String name, int defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return (int)value.getInteger();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public long getAttribute(String name, long defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getInteger();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float getAttribute(String name, float defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return (float)value.getReal();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public double getAttribute(String name, double defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getReal();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public String getAttribute(String name, String defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getString();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public UUID getAttribute(String name, UUID defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getUUID();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public URL getAttribute(String name, URL defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getURL();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public URI getAttribute(String name, URI defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getURI();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Image getAttribute(String name, Image defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getImage();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Date getAttribute(String name, Date defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getDate();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Color getAttribute(String name, Color defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getColor();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public InetAddress getAttribute(String name, InetAddress defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getInetAddress();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public InetAddress getAttribute(String name, InetSocketAddress defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getInetAddress();
+			}
+			catch(AttributeException _) {
+				//
+			}
+		}
+		return defaultValue==null ? null : defaultValue.getAddress();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	@SuppressWarnings("unchecked")
+	public <T extends Enum<T>> T getAttribute(String name, T defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return (T)value.getEnumeration();
+			}
+			catch(AttributeException _) {
+				//
+			}
+			catch(ClassCastException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Class<?> getAttribute(String name, Class<?> defaultValue) {
+		AttributeValue value = getAttribute(name);
+		if (value!=null) {
+			try {
+				return value.getJavaClass();
+			}
+			catch(AttributeException _) {
+				//
+			}
+			catch(ClassCastException _) {
+				//
+			}
+		}
+		return defaultValue;
+	}
+
+}

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractBufferedAttributeProvider.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractBufferedAttributeProvider.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AbstractBufferedAttributeProvider.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,198 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.util.ref.SoftValueTreeMap;
+
+/**
+ * This class implements an abstract attribute container that use
+ * a memory cache.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class AbstractBufferedAttributeProvider extends AbstractAttributeProvider {
+	
+	private transient Map<String,AttributeValue> cache = new SoftValueTreeMap<String,AttributeValue>();
+	
+	/** Make a deep copy of this object and replies the copy.
+	 * 
+	 * @return the deep copy.
+	 */
+	@Override
+	public AbstractBufferedAttributeProvider clone() {
+		AbstractBufferedAttributeProvider clone = (AbstractBufferedAttributeProvider)super.clone();
+		clone.cache = new SoftValueTreeMap<String,AttributeValue>(this.cache);
+		return clone;
+	}
+
+	/** Load a value from the data source.
+	 * 
+	 * @param name is the name of the attribute to load
+	 * @return the value of the attribute.
+	 * @throws AttributeException on error or when the attribute does not exist
+	 */
+	protected abstract AttributeValue loadValue(String name) throws AttributeException;
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public abstract Collection<String> getAllAttributeNames();
+	
+	/** Replies the value associated to the specified name.
+	 */
+	private AttributeValue extractValueFor(String name) throws AttributeException {
+		AttributeValue value = null;
+		if (this.cache.containsKey(name)) {
+			value = this.cache.get(name);
+		}
+		else {
+			value = loadValue(name);
+			this.cache.put(name, value);
+		}
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean hasAttribute(String name) {
+		return getAllAttributeNames().contains(name);
+	}	
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Collection<Attribute> getAllAttributes() {
+		ArrayList<Attribute> list = new ArrayList<Attribute>(getAttributeCount());
+		Attribute newAttr;
+		for(String name : getAllAttributeNames()) {
+			if (name!=null) {
+				try {
+					newAttr = new AttributeImpl(name, extractValueFor(name));
+					list.add(newAttr);
+				}
+				catch(AttributeException _) {
+					//
+				}
+			}
+		}
+		return list;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<AttributeType,Collection<Attribute>> getAllAttributesByType() {
+		TreeMap<AttributeType,Collection<Attribute>> map = new TreeMap<AttributeType,Collection<Attribute>>();
+		Attribute newAttr;
+		for(String name : getAllAttributeNames()) {
+			if (name!=null) {
+				try {
+					newAttr = new AttributeImpl(name, extractValueFor(name));
+					Collection<Attribute> list = map.get(newAttr.getType());
+					if (list==null) {
+						list = new ArrayList<Attribute>();
+						map.put(newAttr.getType(), list);
+					}
+					list.add(newAttr);
+				}
+				catch(AttributeException _) {
+					//
+				}
+			}
+		}
+		return map;
+	}
+
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public AttributeValue getAttribute(String name) {
+		try {
+			return new AttributeValueImpl(extractValueFor(name));
+		}
+		catch(AttributeException _) {
+			//
+		}
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public AttributeValue getAttribute(String name, AttributeValue default_value) {
+		AttributeValue value;
+		try {
+			value = new AttributeValueImpl(extractValueFor(name));
+		}
+		catch(AttributeException _) {
+			value = default_value;
+		}
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute getAttributeObject(String name) {
+		try {
+			return new AttributeImpl(name,extractValueFor(name));
+		}
+		catch(AttributeException _) {
+			//
+		}
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void freeMemory() {
+		this.cache.clear();
+	}
+	
+}
+

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeChangeEvent.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeChangeEvent.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeChangeEvent.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,143 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.EventObject;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+
+/**
+ * This interface representes a listener on the attribute changes
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeChangeEvent extends EventObject { 
+
+	private static final long serialVersionUID = -3573147826440564995L;
+	
+	private final String name;
+	private final String oldName;
+	private final AttributeValue oldValue;
+	private final AttributeValue newValue;
+	private final Type type; 
+
+	/** Create an event that describes a value update only.
+	 * 
+	 * @param source
+	 * @param type
+	 * @param oldName
+	 * @param oldValue
+	 * @param currentName
+	 * @param currentValue
+	 */
+	public AttributeChangeEvent(Object source, Type type, String oldName, AttributeValue oldValue, String currentName, AttributeValue currentValue) {
+		super(source);
+		this.name = currentName;
+		this.oldName = oldName;
+		this.oldValue = oldValue;
+		this.newValue = currentValue;
+		this.type = type;
+	}
+
+	/** Replies the name of the changed attributes.
+	 * 
+	 * @return the name attribute, or <code>null</code> if this
+	 * event has no name attribute.
+	 */
+	public String getName() {
+		return this.name;
+	}
+
+	/** Replies the old name of the changed attributes.
+	 * 
+	 * @return the old name attribute, or <code>null</code> if this
+	 * event has no old name attribute.
+	 */
+	public String getOldName() {
+		return this.oldName;
+	}
+
+	/** Replies the old value of the attribute.
+	 * 
+	 * @return the attribute value or <code>null</code>
+	 */
+	public AttributeValue getOldValue() {
+		return this.oldValue;
+	}
+
+	/** Replies the new value of the attribute.
+	 * 
+	 * @return the attribute value, never <code>null</code>
+	 */
+	public AttributeValue getValue() {
+		return this.newValue;
+	}
+
+	/** Replies the changed attribute.
+	 * 
+	 * @return the attribute, never <code>null</code>
+	 */
+	public Attribute getAttribute() {
+		return new AttributeImpl(this.name,this.newValue);
+	}
+	
+	/** Replies the type of event.
+	 * 
+	 * @return the type of the event, neither <code>null</code>
+	 */
+	public Type getType() {
+		return this.type;
+	}
+
+	/**
+	 * This interface representes a listener on the attribute changes
+	 * 
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public enum Type {
+		/** An attribute value has changed.
+		 */
+		VALUE_UPDATE,
+		/** An attribute was removed.
+		 */
+		REMOVAL,
+		/** an attribute was added.
+		 */
+		ADDITION,
+		/** An attribute was renamed.
+		 */
+		RENAME,
+		/** All attributes were removed.
+		 */
+		REMOVE_ALL;
+	}
+
+}

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeChangeListener.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeChangeListener.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeChangeListener.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,43 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.EventListener;
+
+/**
+ * This interface representes a listener on the attribute changes
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface AttributeChangeListener extends EventListener { 
+
+	/** Invoked when the attribute's value changed.
+	 * 
+	 * @param event describes the changes.
+	 */
+	public void onAttributeChangeEvent(AttributeChangeEvent event);
+
+}

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeCollection.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeCollection.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeCollection.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,341 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+
+/**
+ * This interface representes an object that owns a
+ * collection of attributes with a reading and a
+ * writing API.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface AttributeCollection extends AttributeProvider { 
+
+	/** Make a deep copy of this object and replies the copy.
+	 * 
+	 * @return the deep copy.
+	 */
+	@Override
+	public AttributeCollection clone();
+	
+	/** Set the content of this collection from the given map.
+	 * Any previous content of this attribute collection will
+	 * be lost.
+	 * This function is equivalent to:
+	 * <pre><code>
+	 * this.removeAllAttributes();
+	 * this.addAttributes(content);
+	 * </code></pre>
+	 * 
+	 * @param content is the content.
+	 * @see #addAttributes(Map)
+	 */
+	public void setAttributes(Map<String,Object> content);
+
+	/** Set the content of this collection from the given map.
+	 * Any previous content of this attribute collection will
+	 * be lost.
+	 * This function is equivalent to:
+	 * <pre><code>
+	 * this.removeAllAttributes();
+	 * this.addAttributes(content);
+	 * </code></pre>
+	 * 
+	 * @param content is the content.
+	 * @throws AttributeException if one attribute from the content cannot be inserted. 
+	 * @see #addAttributes(AttributeProvider)
+	 */
+	public void setAttributes(AttributeProvider content) throws AttributeException;
+
+	/** Put the values given as parameter in this attribute provider.
+	 * Any previous content of this attribute collection will remain
+	 * if the keys are not inside the given content.
+	 * If the values from the given content will be used to overwrite
+	 * any existing value.
+	 * 
+	 * @param content is the content to add inside.
+	 * @see #setAttributes(Map)
+	 */
+	public void addAttributes(Map<String,Object> content);
+
+	/** Put the values given as parameter in this attribute provider.
+	 * Any previous content of this attribute collection will remain
+	 * if the keys are not inside the given content.
+	 * If the values from the given content will be used to overwrite
+	 * any existing value.
+	 * 
+	 * @param content is the content to add inside.
+	 * @see #addAttributes(AttributeProvider)
+	 * @throws AttributeException if one attribute from the content cannot be inserted. 
+	 */
+	public void addAttributes(AttributeProvider content) throws AttributeException;
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 * @throws AttributeException on error.
+	 */
+	public Attribute setAttribute(String name, AttributeValue value) throws AttributeException;
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, boolean value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, int value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, long value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, float value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, double value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, String value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, UUID value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, URL value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, URI value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, Image value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, Date value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, Color value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, InetAddress value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, InetSocketAddress value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, Enum<?> value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param name is the name of the attribute to set.
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 */
+	public Attribute setAttribute(String name, Class<?> value);
+
+	/** Set the value for the given attribute.
+	 * 
+	 * @param value is the value to store.
+	 * @return the changed attribute or <code>null</code>
+	 * @throws AttributeException 
+	 */
+	public Attribute setAttribute(Attribute value) throws AttributeException;
+
+	/** Set the type of the attribute with the given name.
+	 * 
+	 * @param name is the name of the attribute
+	 * @param type is the desired type.
+	 * @return the changed attribute or <code>null</code>
+	 * @throws AttributeException 
+	 * @since 4.0
+	 */
+	public Attribute setAttributeType(String name, AttributeType type) throws AttributeException;
+
+	/** Remove the given attribute.
+	 * 
+	 * @param name is the name of the attribute to remove.
+	 * @return <code>true</code> on success, otherwhise <code>false</code>
+	 */
+	public boolean removeAttribute(String name);
+
+	/** Remove all the attributes.
+	 * 
+	 * @return <code>false</code> if something wrong appends
+	 */
+	public boolean removeAllAttributes();
+	
+	/** Rename the attribute.
+	 * <p>
+	 * If a attribute named <code>newname</code> already exists,
+	 * this function will reply <code>false</code>.
+	 * <p>
+	 * This function is equivalent to {@code renameAttribute(oldname,newname,false)}.
+	 * 
+	 * @param oldname is the name of the attribute to rename.
+	 * @param newname is the new name of the attribute.
+	 * @return <code>false</code> if something wrong appends
+	 */
+	public boolean renameAttribute(String oldname, String newname);
+
+	/** Rename the attribute .
+	 *
+	 * @param oldname is the name of the attribute to rename.
+	 * @param newname is the new name of the attribute.
+	 * @param overwrite must be <code>true</code> if the value of an
+	 * existing attribute named by <code>newname</code> must be
+	 * overwritten by the value of the attribute named <code>oldname</code>. 
+	 * @return <code>false</code> if something wrong appends
+	 */
+	public boolean renameAttribute(String oldname, String newname, boolean overwrite);
+
+	/** Copy the attributes from another container into this provider.
+	 * 
+	 * @param otherContainer is the container of attributes to copy.
+	 * @throws AttributeException on error.
+	 */
+	public void copyFrom(AttributeProvider otherContainer) throws AttributeException;
+
+	/** Add a listener on the attribute value changes.
+	 * 
+	 * @param listener
+	 */
+	public void addAttributeChangeListener(AttributeChangeListener listener);
+
+	/** Remove a listener on the attribute value changes.
+	 * 
+	 * @param listener
+	 */
+	public void removeAttributeChangeListener(AttributeChangeListener listener);
+	
+	/** Replies if the events are fired by this container.
+	 * 
+	 * @return <code>true</code> if the events are fired; otherwise <code>false</code>
+	 * if events are not fired.
+	 */
+	public boolean isEventFirable();
+	
+	/** Set if the events are fired by this container.
+	 * 
+	 * @param isFirable is <code>true</code> if the events are fired; otherwise <code>false</code>
+	 * if events are not fired.
+	 */
+	public void setEventFirable(boolean isFirable);
+
+	/** Force this provider to synchronized the memory state of the attributes
+	 * with a remote storage area.
+	 */
+	public void flush();
+
+}

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeIterator.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeIterator.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeIterator.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,100 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+
+/**
+ * Iterator on attributes.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeIterator implements Iterator<Attribute> {
+	
+	private AttributeProvider provider;
+	private final ArrayList<String> names = new ArrayList<String>();
+	private String lastName = null; 
+	
+	/**
+	 * Create an iterator on the given container.
+	 * 
+	 * @param provider is the container of attributes.
+	 */
+	public AttributeIterator(AttributeProvider provider) {
+		this.provider = provider;
+		this.names.addAll(provider.getAllAttributeNames());
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean hasNext() {
+		if ((this.provider==null)||(this.names.isEmpty())) {
+			this.provider = null;
+			return false;
+		}
+		return true;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Attribute next() {
+		if ((this.provider==null)||(this.names.isEmpty()))
+			throw new NoSuchElementException();
+		
+		String name = this.names.remove(0);
+		if (name==null)
+			throw new NoSuchElementException();
+		
+		Attribute attr = this.provider.getAttributeObject(name);
+		if (attr==null)
+			throw new NoSuchElementException();
+		
+		this.lastName = name;
+		
+		if (this.names.isEmpty())
+			this.provider = null;
+		
+		return attr;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void remove() {
+		if ((this.provider==null)||(this.lastName==null))
+			throw new NoSuchElementException();
+		if (this.provider instanceof AttributeCollection)
+			((AttributeCollection)this.provider).removeAttribute(this.lastName);
+		this.lastName = null;
+	}
+	
+}

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeNameStringComparator.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeNameStringComparator.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeNameStringComparator.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,47 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.Comparator;
+
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+
+
+/**
+ * Comparator for attribute names as strings.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+class AttributeNameStringComparator implements Comparator<String> {
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public int compare(String arg0, String arg1) {
+		return AttributeImpl.compareAttrNames(arg0, arg1);
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeProvider.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeProvider.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/AttributeProvider.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,421 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+
+/**
+ * This interface representes a provider of attributes
+ * that provide a reading API only.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface AttributeProvider { 
+
+	/** Make a deep copy of this object and replies the copy.
+	 * 
+	 * @return the deep copy.
+	 */
+	public AttributeProvider clone();
+
+	/** Replies the count of attributes
+	 * 
+	 * @return the count of attributes.
+	 */
+	public int getAttributeCount();
+
+	/** Replies if the given attribute exists.
+	 * 
+	 * @param name
+	 * @return <code>true</code> is an attribute with the given name exists, otherwise <code>false</code>
+	 */
+	public boolean hasAttribute(String name);
+
+	/** Replies all the attributes.
+	 * 
+	 * @return the list of all attributes
+	 */
+	public Collection<Attribute> getAllAttributes();
+	
+	/** Replies all the attributes.
+	 * 
+	 * @return an iterable object that contains the attributes.
+	 */
+	public Iterable<Attribute> attributes();
+
+	/** Replies all the attributes sorted by type.
+	 * <p>
+	 * The keys of the returned hashtable are the types and
+	 * the values are array of attributes ({@link java.util.Vector}).
+	 * 
+	 * @return the attributes grouped by type.
+	 */
+	public Map<AttributeType,Collection<Attribute>> getAllAttributesByType();
+
+	/** Replies all the attribute names.
+	 * This function never load the attribute values even
+	 * if they are not inside the storage layer.
+	 * 
+	 * @return the list of all attribute names.
+	 */
+	public Collection<String> getAllAttributeNames();
+
+	/** Replies the value for the given attribute.
+	 *
+	 * @param name
+	 * @return the value or <code>null</code>
+	 */
+	public AttributeValue getAttribute(String name);
+
+	/** Replies the attribute with the given name.
+	 * 
+	 * @param name
+	 * @return the attribute or <code>null</code>
+	 */
+	public Attribute getAttributeObject(String name);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public boolean getAttributeAsBool(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public int getAttributeAsInt(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public long getAttributeAsLong(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public float getAttributeAsFloat(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public double getAttributeAsDouble(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public String getAttributeAsString(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public UUID getAttributeAsUUID(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public URL getAttributeAsURL(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public URI getAttributeAsURI(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public Image getAttributeAsImage(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public Date getAttributeAsDate(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public Color getAttributeAsColor(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public InetAddress getAttributeAsInetAddress(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public Enum<?> getAttributeAsEnumeration(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param <T> is the type of the enumeration to retreive.
+	 * @param name
+	 * @param type is the type of the enumeration to retreive.
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public <T extends Enum<T>> T getAttributeAsEnumeration(String name, Class<T> type) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @return the value
+	 * @throws AttributeException if the attribute was never set.
+	 */
+	public Class<?> getAttributeAsJavaClass(String name) throws AttributeException;
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public boolean getAttribute(String name, boolean defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public int getAttribute(String name, int defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public long getAttribute(String name, long defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public float getAttribute(String name, float defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public double getAttribute(String name, double defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public String getAttribute(String name, String defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public UUID getAttribute(String name, UUID defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public URL getAttribute(String name, URL defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public URI getAttribute(String name, URI defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public Image getAttribute(String name, Image defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public Date getAttribute(String name, Date defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public Color getAttribute(String name, Color defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value or <code>null</code>
+	 */
+	public AttributeValue getAttribute(String name, AttributeValue defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public InetAddress getAttribute(String name, InetAddress defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public InetAddress getAttribute(String name, InetSocketAddress defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param <T> is the type of the enumeration.
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public <T extends Enum<T>> T getAttribute(String name, T defaultValue);
+
+	/** Replies the value for the given attribute.
+	 * 
+	 * @param name
+	 * @param defaultValue is the default value replied if the attribute
+	 * has no value.
+	 * @return the value
+	 */
+	public Class<?> getAttribute(String name, Class<?> defaultValue);
+
+	/** Clean the internal memory-storage structures if they exist.
+	 * <p>
+	 * This function permits to limit the memory usage without
+	 * removing the attribute value from a hard storage area (database,
+	 * files...). The attribute which are freed by this method could
+	 * be reloaded in memory with a call to a getting method.
+	 */
+	public void freeMemory();
+
+	/** Replies the map of the values stored in this attribute provider.
+	 * The replied map is a copy of or an unmodifiable version
+	 * of the internal map, if it exists.q
+	 * 
+	 * @return the map, never <code>null</code>.
+	 */
+	public Map<String,Object> toMap();
+	
+	/** Fill the given map with the values stored in this attribute provider.
+	 * 
+	 * @param mapToFill is the map to fill, never <code>null</code>.
+	 */
+	public void toMap(Map<String,Object> mapToFill);
+
+}

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/BufferedAttributeCollection.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/BufferedAttributeCollection.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/BufferedAttributeCollection.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,627 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+import org.arakhne.util.ref.SoftValueTreeMap;
+
+/**
+ * This class implements an abstract attribute provider that use
+ * a memory cache.
+ * 
+ * XXX: Make this provider to save asynchronously on the remote storage area.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class BufferedAttributeCollection extends AbstractAttributeCollection {
+	
+	private transient Map<String,AttributeValue> cache = new SoftValueTreeMap<String,AttributeValue>();
+	
+	/** Make a deep copy of this object and replies the copy.
+	 * 
+	 * @return the deep copy.
+	 */
+	@Override
+	public BufferedAttributeCollection clone() {
+		BufferedAttributeCollection clone = (BufferedAttributeCollection)super.clone();
+		this.cache = new SoftValueTreeMap<String,AttributeValue>();
+		return clone;
+	}
+
+	/** Load a value from the data source.
+	 * 
+	 * @param name is the name of the attribute to load
+	 * @return the value of the attribute.
+	 * @throws AttributeException on error or when the attribute does not exist
+	 */
+	protected abstract AttributeValue loadValue(String name) throws AttributeException;
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public abstract Collection<String> getAllAttributeNames();
+	
+	/** Save a value into the data source.
+	 * 
+	 * @param name is the name of the attribute to save
+	 * @param value is the value of the attribute.
+	 * @throws AttributeException on error.
+	 */
+	protected abstract void saveValue(String name, AttributeValue value) throws AttributeException;
+
+	/** Remove a value from the data source.
+	 * 
+	 * @param name is the name of the attribute to remove
+	 * @return the removed value
+	 * @throws AttributeException on error
+	 */
+	protected abstract AttributeValue removeValue(String name) throws AttributeException;
+
+	/** Remove all the values from the data source.
+	 * 
+	 * @return <code>true</code> on success, otherwhise <code>false</code>
+	 * @throws AttributeException on error
+	 */
+	protected abstract boolean removeAllValues() throws AttributeException;
+
+	/** Replies the value associated to the specified name.
+	 * @throws AttributeException 
+	 */
+	private AttributeValue extractValueFor(String name) throws AttributeException {
+		AttributeValue value = null;
+		if (this.cache.containsKey(name)) {
+			value = this.cache.get(name);
+		}
+		else {
+			value = loadValue(name);
+			this.cache.put(name, value);
+		}
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean hasAttribute(String name) {
+		return getAllAttributeNames().contains(name);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Collection<Attribute> getAllAttributes() {
+		ArrayList<Attribute> list = new ArrayList<Attribute>(getAttributeCount());
+		Attribute newAttr;
+		for(String name : getAllAttributeNames()) {
+			if (name!=null) {
+				try {
+					newAttr = new AttributeImpl(name, extractValueFor(name));
+					list.add(newAttr);
+				}
+				catch(AttributeException _) {
+					//
+				}
+			}
+		}
+		return list;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<AttributeType,Collection<Attribute>> getAllAttributesByType() {
+		TreeMap<AttributeType,Collection<Attribute>> map = new TreeMap<AttributeType,Collection<Attribute>>();
+		Attribute newAttr;
+		for(String name : getAllAttributeNames()) {
+			if (name!=null) {
+				try {
+					newAttr = new AttributeImpl(name, extractValueFor(name));
+					Collection<Attribute> list = map.get(newAttr.getType());
+					if (list==null) {
+						list = new ArrayList<Attribute>();
+						map.put(newAttr.getType(), list);
+					}
+					list.add(newAttr);
+				}
+				catch(AttributeException _) {
+					//
+				}
+			}
+		}
+		return map;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public AttributeValue getAttribute(String name) {
+		try {
+			return new AttributeValueImpl(extractValueFor(name));
+		}
+		catch(AttributeException _) {
+			//
+		}
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public AttributeValue getAttribute(String name, AttributeValue default_value) {
+		AttributeValue value;
+		try {
+			value = new AttributeValueImpl(extractValueFor(name));
+		}
+		catch(AttributeException _) {
+			value = default_value;
+		}
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute getAttributeObject(String name) {
+		try {
+			return new AttributeImpl(name,extractValueFor(name));
+		}
+		catch(AttributeException _) {
+			//
+		}
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void freeMemory() {
+		this.cache.clear();
+	}
+	
+	/** Set the attribute value.
+	 * 
+	 * @param name is the name of the attribute
+	 * @param value is the raw value to store.
+	 * @return the new created attribute
+	 * @throws AttributeException 
+	 */
+	protected Attribute setAttributeFromRawValue(String name, AttributeValue value) throws AttributeException {
+		return setAttributeFromRawValue(name, value.getType(), value.getValue());
+	}
+
+	/** Set the attribute value.
+	 * 
+	 * @param name is the name of the attribute
+	 * @param type is the type of the attribute
+	 * @param value is the raw value to store.
+	 * @return the new created attribute
+	 * @throws AttributeException 
+	 */
+	protected Attribute setAttributeFromRawValue(String name, AttributeType type, Object value) throws AttributeException {
+		AttributeValue oldValue;
+		try {
+			oldValue = new AttributeValueImpl(extractValueFor(name));
+		}
+		catch(AttributeException _) {
+			oldValue = null;
+		}
+				
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		Attribute attr = new AttributeImpl(name,type);
+		attr.setValue(type.cast(value));
+
+		saveValue(name,attr);
+	
+		this.cache.put(name, attr);	
+		
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttributeType(String name, AttributeType type) throws AttributeException {
+		AttributeValue oldValue;
+		try {
+			oldValue = new AttributeValueImpl(extractValueFor(name));
+		}
+		catch(AttributeException _) {
+			oldValue = null;
+		}
+		AttributeType oldType = (oldValue==null) ? null : oldValue.getType();
+
+		if (oldValue==null || oldType==null || type==null || type==oldType) return null;
+		
+		Attribute attr = new AttributeImpl(name,oldValue.getValue());
+		attr.cast(type);
+		
+		this.cache.put(name, attr);
+		
+		fireAttributeChangedEvent(name, oldValue, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, AttributeValue value) throws AttributeException {
+		return setAttributeFromRawValue(name, value);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, boolean value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.BOOLEAN, Boolean.valueOf(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, int value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.INTEGER, Long.valueOf(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, long value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.INTEGER, Long.valueOf(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, float value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.REAL, Double.valueOf(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, double value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.REAL, Double.valueOf(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, String value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.STRING, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, UUID value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.UUID, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, URL value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.URL, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, URI value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.URI, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Image value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.IMAGE, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Date value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.DATE, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Color value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.COLOR, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, InetAddress value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.INET_ADDRESS, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, InetSocketAddress value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.INET_ADDRESS, value==null ? null : value.getAddress());
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Enum<?> value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.ENUMERATION, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Class<?> value) {
+		try {
+			return setAttributeFromRawValue(name, AttributeType.TYPE, value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(Attribute value) throws AttributeException {
+		return setAttributeFromRawValue(value.getName(), value);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean removeAttribute(String name) {
+		try {
+			if (hasAttribute(name)) {
+				AttributeValue currentValue = extractValueFor(name);
+				this.cache.remove(name);
+				removeValue(name);
+				fireAttributeRemovedEvent(name,currentValue);
+				return true;
+			}
+		}
+		catch(AttributeException _) {
+			//
+		}
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean removeAllAttributes() {
+		try {
+			if (getAttributeCount()>0) {
+				this.cache.clear();
+				if (removeAllValues()) {
+					fireAttributeClearedEvent();
+					return true;
+				}
+			}
+		}
+		catch(AttributeException _) {
+			//
+		}
+		return false;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean renameAttribute(String oldname, String newname, boolean overwrite) {
+		try {
+			AttributeValue valueForOldName = null;
+			
+			try {
+				valueForOldName = extractValueFor(oldname);
+			}
+			catch(AttributeException _) {
+				//
+			}
+
+			// The source attribute does not exist.
+			if (valueForOldName==null) return false;
+			
+			AttributeValue oldValueForNewName = null;
+			
+			try {
+				oldValueForNewName = extractValueFor(newname);
+			}
+			catch(AttributeException _) {
+				//
+			}
+			
+			// Target attribute is existing and overwrite was disabled.
+			if ((!overwrite)&&(oldValueForNewName!=null)) return false;
+			
+			AttributeValue oldValueCopyForNewName = new AttributeValueImpl(oldValueForNewName);
+			
+			removeValue(oldname);
+			this.cache.remove(oldname);
+			if (valueForOldName instanceof Attribute) {
+				((Attribute)valueForOldName).setName(newname);
+			}
+			saveValue(newname, valueForOldName);
+			this.cache.put(newname, valueForOldName);
+			
+			if (oldValueForNewName!=null)
+				fireAttributeRemovedEvent(newname,oldValueCopyForNewName);
+			
+			fireAttributeRenamedEvent(oldname,newname,valueForOldName);
+			
+			return true;
+		}
+		catch(AttributeException _) {
+			//
+		}
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void flush() {
+		//
+	}
+
+}
+

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/HeapAttributeCollection.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/HeapAttributeCollection.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/HeapAttributeCollection.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,873 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.UUID;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeNotInitializedException;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.attrs.attr.InvalidAttributeTypeException;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+
+/**
+ * This class implements an attribute provider which
+ * only works with the Heap space.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class HeapAttributeCollection extends AbstractAttributeCollection {
+	
+	private Map<String,Object> heap = new TreeMap<String,Object>(new AttributeNameStringComparator());
+	
+	/** Make a deep copy of this object and replies the copy.
+	 * 
+	 * @return the deep copy.
+	 */
+	@Override
+	public HeapAttributeCollection clone() {
+		HeapAttributeCollection clone = (HeapAttributeCollection)super.clone();
+		clone.heap = new TreeMap<String,Object>(new AttributeNameStringComparator());
+		clone.heap.putAll(this.heap);
+		return clone;
+	}
+
+	@Override
+	public void addAttributes(Map<String, Object> content) {
+		Object value, oldValue;
+		AttributeType type;
+		for(Entry<String,Object> pair : content.entrySet()) {
+			value = pair.getValue();
+			type = AttributeType.fromValue(value);
+			value = type.cast(value);
+			oldValue = this.heap.put(pair.getKey(), value);
+			if (oldValue==null) {
+				fireAttributeAddedEvent(pair.getKey(), new AttributeValueImpl(type, value));
+			}
+			else {
+				fireAttributeChangedEvent(pair.getKey(),
+						new AttributeValueImpl(type, oldValue),
+						new AttributeValueImpl(type, value));
+			}
+		}
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void addAttributes(AttributeProvider content) throws AttributeException {
+		Object value, oldValue;
+		for(Attribute attr : content.attributes()) {
+			value = attr.getValue();
+			oldValue = this.heap.put(attr.getName(), value);
+			if (oldValue==null) {
+				fireAttributeAddedEvent(attr.getName(),
+						new AttributeValueImpl(attr.getType(), value));
+			}
+			else {
+				fireAttributeChangedEvent(attr.getName(),
+						new AttributeValueImpl(AttributeType.fromValue(oldValue), oldValue),
+						new AttributeValueImpl(attr.getType(), value));
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setAttributes(Map<String, Object> content) {
+		setAttributesInternal(new TreeMap<String,Object>(content));
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setAttributes(AttributeProvider content) throws AttributeException {
+		Map<String,Object> newAttributes = new TreeMap<String,Object>();
+		content.toMap(newAttributes);
+		setAttributesInternal(newAttributes);
+	}
+
+	private void setAttributesInternal(Map<String, Object> newAttributes) {
+		Iterator<Entry<String,Object>> iterator = this.heap.entrySet().iterator();
+		Entry<String,Object> entry;
+		Object newValue;
+		AttributeType type;
+		while (iterator.hasNext()) {
+			entry = iterator.next();
+			newValue = newAttributes.remove(entry.getKey());
+			if (newValue==null) {
+				iterator.remove();
+				fireAttributeRemovedEvent(entry.getKey(),
+						new AttributeValueImpl(AttributeType.fromValue(entry.getValue()), entry.getValue()));
+			}
+			else {
+				type = AttributeType.fromValue(newValue);
+				newValue = type.cast(newValue);
+				entry.setValue(newValue);
+				fireAttributeChangedEvent(entry.getKey(),
+						new AttributeValueImpl(AttributeType.fromValue(entry.getValue()), entry.getValue()),
+						new AttributeValueImpl(type, newValue));
+			}
+		}
+		
+		for(Entry<String,Object> e : newAttributes.entrySet()) {
+			newValue = e.getValue();
+			type = AttributeType.fromValue(newValue);
+			newValue = type.cast(newValue);
+			if (newValue!=null) {
+				this.heap.put(e.getKey(), newValue);
+				fireAttributeAddedEvent(e.getKey(),
+						new AttributeValueImpl(type, newValue));
+			}
+		}
+	}
+			
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void toMap(Map<String,Object> mapToFill) {
+		mapToFill.putAll(this.heap);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int getAttributeCount() {
+		return this.heap.size();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean hasAttribute(String name) {
+		return this.heap.containsKey(name);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Collection<Attribute> getAllAttributes() {
+		ArrayList<Attribute> list = new ArrayList<Attribute>(getAttributeCount());
+		String name;
+		AttributeImpl newAttr;
+		Object rawValue;
+		for(Entry<String, Object> entry : this.heap.entrySet()) {
+			name = entry.getKey();
+			if (name!=null) {
+				rawValue = entry.getValue();
+				newAttr = new AttributeImpl(name);
+				newAttr.castAndSet(
+						AttributeType.fromValue(rawValue),
+						unprotectNull(rawValue));
+				list.add(newAttr);
+			}
+		}
+		return list;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<AttributeType,Collection<Attribute>> getAllAttributesByType() {
+		TreeMap<AttributeType,Collection<Attribute>> map = new TreeMap<AttributeType,Collection<Attribute>>();
+		AttributeType type;
+		Attribute attr;
+		Object value;
+		for(Entry<String,Object> entry : this.heap.entrySet()) {
+			value = entry.getValue(); 
+			if (value!=null) {
+				type = AttributeType.fromValue(value);
+				value = unprotectNull(value);
+				Collection<Attribute> list = map.get(type);
+				if (list==null) {
+					list = new ArrayList<Attribute>();
+					map.put(type, list);
+				}
+				attr = new AttributeImpl(entry.getKey());
+				attr.castAndSet(type, value);
+				list.add(attr);
+			}
+		}
+		return map;
+	}
+
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Collection<String> getAllAttributeNames() {
+		return Collections.unmodifiableCollection(this.heap.keySet());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public AttributeValue getAttribute(String name) {
+		return getStoredAttributeValue(name,null);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public AttributeValue getAttribute(String name, AttributeValue default_value) {
+		AttributeValue value = getStoredAttributeValue(name,
+				default_value==null ? null : default_value.getType());
+		if (value==null) return default_value;
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute getAttributeObject(String name) {
+		return getStoredAttribute(name,null);
+	}
+
+	/** Replies the attribute with the given name.
+	 * 
+	 * @param name is the name of the attribute to retreive
+	 * @param expectedType is the expected type for the attribute.
+	 * @return the value or <code>null</code>
+	 */
+	protected Attribute getStoredAttribute(String name, AttributeType expectedType) {
+		Object val = this.heap.get(name);
+		if (val!=null) {
+			AttributeType currentType = AttributeType.fromValue(val);
+			val = unprotectNull(val);
+			Attribute attr = new AttributeImpl(name);
+			if (expectedType==null)
+				attr.castAndSet(currentType,val);
+			else
+				attr.castAndSet(expectedType,val);
+			return attr;
+		}
+		return null;
+	}
+
+	/** Replies the attribute with the given name.
+	 * 
+	 * @param name is the name of the attribute to retreive
+	 * @param expectedType is the expected type for the attribute.
+	 * @return the value or <code>null</code>
+	 */
+	protected AttributeValue getStoredAttributeValue(String name, AttributeType expectedType) {
+		Object val = this.heap.get(name);
+		if (val!=null) {
+			AttributeType currentType = AttributeType.fromValue(val);
+			val = unprotectNull(val);
+			AttributeValue attr = new AttributeValueImpl(name);
+			if (expectedType==null)
+				attr.castAndSet(currentType, val);
+			else
+				attr.castAndSet(expectedType,val);
+			return attr;
+		}
+		return null;
+	}
+	
+	private AttributeValue copyValue(String name) {
+		AttributeValue oldValue = null;
+		Object currentValue = this.heap.get(name);
+		if (currentValue!=null) {
+			AttributeType oldType = AttributeType.fromValue(currentValue);
+			oldValue = new AttributeValueImpl();
+			oldValue.castAndSet(oldType, currentValue);
+			return oldValue;
+		}
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttributeType(String name, AttributeType type) throws AttributeException {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		AttributeType oldType = (oldValue==null) ? null : oldValue.getType();
+	
+		if (oldType==null || type==null || oldType==type) return null;
+		
+		Attribute attr = new AttributeImpl(name,(oldValue==null) ? null : oldValue.getValue());
+		attr.cast(type);
+		
+		this.heap.put(name, protectNull(attr.getValue(), type));
+		
+		fireAttributeChangedEvent(name, oldValue, attr);
+
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, AttributeValue value) throws AttributeException {
+		assert(name!=null && value!=null);
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, protectNull(value.getValue(), value.getType()));
+		
+		Attribute attr = new AttributeImpl(name,value.getValue());
+
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, value);
+		else
+			fireAttributeAddedEvent(name, attr);
+
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, boolean value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, Boolean.valueOf(value));
+		
+		Attribute attr = new AttributeImpl(name,value);
+		
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, int value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, Long.valueOf(value));
+		
+		Attribute attr = new AttributeImpl(name,value);		
+		
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, long value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, Long.valueOf(value));
+		
+		Attribute attr = new AttributeImpl(name,value);		
+		
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, float value) {
+		assert(name!=null);
+
+		AttributeValue oldValue;
+		Object currentValue = this.heap.get(name);
+		if (currentValue!=null) {
+			oldValue = new AttributeValueImpl();
+			oldValue.castAndSet(AttributeType.fromValue(currentValue), currentValue);
+		}
+		else {
+			oldValue = null;
+		}
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, Double.valueOf(value));
+		
+		Attribute attr = new AttributeImpl(name,value);		
+		
+		if (currentValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, double value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, Double.valueOf(value));
+		
+		Attribute attr = new AttributeImpl(name,value);		
+		
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, String value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		Object rv = (value==null) ? AttributeType.STRING.getDefaultValue() : value;
+		this.heap.put(name, rv);
+		
+		Attribute attr = new AttributeImpl(name,rv);
+		
+		if (oldValue!=null) {
+			fireAttributeChangedEvent(name, oldValue, attr);
+		}
+		else {
+			fireAttributeAddedEvent(name, attr);
+		}
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, UUID value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		Object rv = (value==null) ? AttributeType.UUID.getDefaultValue() : value;
+		this.heap.put(name, rv);
+		
+		Attribute attr = new AttributeImpl(name,rv);
+		
+		if (oldValue!=null) {
+			fireAttributeChangedEvent(name, oldValue, attr);
+		}
+		else {
+			fireAttributeAddedEvent(name, attr);
+		}
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, URL value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, protectNull(value, AttributeType.URL));
+		
+		Attribute attr = new AttributeImpl(name,value);
+		
+		if (oldValue!=null) {
+			fireAttributeChangedEvent(name, oldValue, attr);
+		}
+		else {
+			fireAttributeAddedEvent(name, attr);
+		}
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, URI value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, protectNull(value, AttributeType.URI));
+		
+		Attribute attr = new AttributeImpl(name,value);
+		
+		if (oldValue!=null) {
+			fireAttributeChangedEvent(name, oldValue, attr);
+		}
+		else {
+			fireAttributeAddedEvent(name, attr);
+		}
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Image value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, protectNull(value, AttributeType.IMAGE));
+		
+		Attribute attr = new AttributeImpl(name,value);
+		
+		if (oldValue!=null) {
+			fireAttributeChangedEvent(name, oldValue, attr);
+		}
+		else {
+			fireAttributeAddedEvent(name, attr);
+		}
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Date value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		Object rv = (value==null) ? AttributeType.DATE.getDefaultValue() : value;
+		this.heap.put(name, rv);
+		
+		Attribute attr = new AttributeImpl(name,rv);
+		
+		if (oldValue!=null) {
+			fireAttributeChangedEvent(name, oldValue, attr);
+		}
+		else {
+			fireAttributeAddedEvent(name, attr);
+		}
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Color value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		Object rv = (value==null) ? AttributeType.COLOR.getDefaultValue() : value;
+		this.heap.put(name, rv);
+		
+		Attribute attr = new AttributeImpl(name,rv);
+		
+		if (oldValue!=null) {
+			fireAttributeChangedEvent(name, oldValue, attr);
+		}
+		else {
+			fireAttributeAddedEvent(name, attr);
+		}
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(Attribute value) throws AttributeException {
+		assert(value!=null);
+		String name = value.getName();
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+		
+		this.heap.put(name, protectNull(value.getValue(), value.getType()));
+
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, value);
+		else
+			fireAttributeAddedEvent(name, value);
+		
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, InetAddress value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, value);
+		
+		Attribute attr = new AttributeImpl(name,value);
+		
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, InetSocketAddress value) {
+		return setAttribute(name, (value==null) ? null : value.getAddress());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Enum<?> value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, value);
+		
+		Attribute attr = new AttributeImpl(name,value);
+		
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Class<?> value) {
+		assert(name!=null);
+
+		AttributeValue oldValue = copyValue(name);
+		
+		if (oldValue!=null && oldValue.equals(value)) return null;
+
+		this.heap.put(name, value);
+		
+		Attribute attr = new AttributeImpl(name,value);
+		
+		if (oldValue!=null)
+			fireAttributeChangedEvent(name, oldValue, attr);
+		else
+			fireAttributeAddedEvent(name, attr);
+		
+		return attr;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean removeAttribute(String name) {
+		assert(name!=null);
+
+		AttributeValue oldValue;
+		Object currentValue = this.heap.remove(name);
+		if (currentValue!=null) {
+			oldValue = new AttributeValueImpl();
+			oldValue.castAndSet(AttributeType.fromValue(currentValue), currentValue);
+			fireAttributeRemovedEvent(name,oldValue);
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean removeAllAttributes() {
+		if (!this.heap.isEmpty()) {
+			this.heap.clear();
+			fireAttributeClearedEvent();
+			return true;
+		}
+		return false;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean renameAttribute(String oldname, String newname, boolean overwrite) {
+		if (oldname==null || newname==null || oldname.equals(newname)) return false;
+		
+		AttributeValue valueOfOldName = copyValue(oldname);
+		
+		// The attribute does not exist.
+		if (valueOfOldName==null) return false;
+		
+		AttributeValue oldValueOfNewName = copyValue(newname);
+		
+		// The target attribute is existing and overwrite was disabled
+		if ((!overwrite)&&(oldValueOfNewName!=null)) return false;
+		
+		Object rawValue;
+		
+		try {
+			rawValue = valueOfOldName.getValue();
+		}
+		catch (InvalidAttributeTypeException e) {
+			rawValue = null;
+		}
+		catch (AttributeNotInitializedException e) {
+			rawValue = null;
+		}
+
+		this.heap.remove(oldname);
+		this.heap.put(newname, protectNull(rawValue, valueOfOldName.getType()));
+		
+		if (oldValueOfNewName!=null)
+			fireAttributeRemovedEvent(newname,oldValueOfNewName);
+		
+		fireAttributeRenamedEvent(oldname,newname,valueOfOldName);
+		
+		return true;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void freeMemory() {
+		// Do nothing
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void flush() {
+		// Do nothing
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		return this.heap.toString();
+	}
+
+}
+

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/MultiAttributeCollection.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/MultiAttributeCollection.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/MultiAttributeCollection.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,732 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeError;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.attrs.collection.AttributeChangeEvent.Type;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+
+/**
+ * This class contains a collection of attribute providers and
+ * tries to gather the data.
+ * This class contains a collection of AttributeProviders and
+ * exhibites the values of the attributes of all these providers.
+ * This class follows the following rules (in that order)
+ * to retreive the value of an attribute:<ol>
+ * <li>If the attribute is defined in none of the containers, throws the standard exception;</li>
+ * <li>If the attribute is defined in only one of the containers, replies the attribute value itself;</li>
+ * <li>If the attribute is defined in more than one container:<ol>
+ * 		<li>if all the values are equal, then replies one of the attribute values;</li>
+ * 		<li>if the values are not equal and all the values have equivalent types (as replied
+ * 			by {@link AttributeType#isAssignableFrom(AttributeType)}), then replies an
+ * 			attribute value with a "undefined" value and of the type of one of the values;</li>
+ * 		<li>if the values are not equal and one of the value has not an equivalent type to
+ * 			the others (as replied by {@link AttributeType#isAssignableFrom(AttributeType)}),
+ * 			then replies an attribute value with a "undefined" value and of the type OBJECT.</li>
+ * 		</ol></li>
+ * </ol>
+ * <p>
+ * If an attribute is set from this AttributeProviderContainer, all the containers inside it
+ * are changed.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 4.0
+ */
+public class MultiAttributeCollection extends MultiAttributeProvider implements AttributeCollection {
+
+	/**
+	 * Boolean indicates that enable event handling from the providers, or not.
+	 */
+	AtomicBoolean runProviderEvents = new AtomicBoolean(true);
+
+	private Handler eventHandler = new Handler();
+	private Collection<AttributeChangeListener> listeners = null;
+	private boolean isEventFirable = true;
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public synchronized boolean isEventFirable() {
+		return this.isEventFirable;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public synchronized void setEventFirable(boolean isFirable) {
+		this.isEventFirable = isFirable;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public MultiAttributeCollection clone() {
+		MultiAttributeCollection clone = (MultiAttributeCollection)super.clone();
+		clone.runProviderEvents = new AtomicBoolean(true);
+		clone.eventHandler = new Handler();
+		clone.listeners = (this.listeners==null) ? null : new ArrayList<AttributeChangeListener>(this.listeners);
+		for(AttributeProvider c : clone.containers()) {
+			if (c instanceof AttributeCollection) {
+				((AttributeCollection)c).addAttributeChangeListener(clone.eventHandler);
+			}
+		}
+		return clone;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean addAttributeContainer(AttributeProvider container) {
+		if (super.addAttributeContainer(container)) {
+			if (container instanceof AttributeCollection)
+				((AttributeCollection)container).addAttributeChangeListener(this.eventHandler);
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean removeAttributeContainer(AttributeProvider container) {
+		if (super.removeAttributeContainer(container)) {
+			if (container instanceof AttributeCollection)
+				((AttributeCollection)container).removeAttributeChangeListener(this.eventHandler);
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void addAttributeChangeListener(AttributeChangeListener listener) {
+		if (this.listeners==null)
+			this.listeners = new ArrayList<AttributeChangeListener>();
+		this.listeners.add(listener);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void removeAttributeChangeListener(AttributeChangeListener listener) {
+		if (this.listeners!=null) {
+			this.listeners.add(listener);
+			if (this.listeners.isEmpty())
+				this.listeners = null;
+		}
+	}
+
+	/** Notifies the listeners about the change of an attribute.
+	 * 
+	 * @param event
+	 */
+	protected void fireAttributeChange(AttributeChangeEvent event) {
+		if (this.listeners!=null && isEventFirable()) {
+			AttributeChangeListener[] list = new AttributeChangeListener[this.listeners.size()];
+			this.listeners.toArray(list);
+			for(AttributeChangeListener listener : list) {
+				listener.onAttributeChangeEvent(event);
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void copyFrom(AttributeProvider otherContainer) throws AttributeException {
+		if (otherContainer!=null) {
+			for(Attribute attr : otherContainer.attributes()) {
+				setAttribute(attr);
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void flush() {
+		for(AttributeProvider c : containers()) {
+			if (c instanceof AttributeCollection) {
+				((AttributeCollection)c).flush();
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean removeAllAttributes() {
+		boolean b = this.runProviderEvents.getAndSet(false);
+		try {
+			boolean changed = false;
+			for(AttributeProvider c : containers()) {
+				if (c instanceof AttributeCollection) {
+					changed = ((AttributeCollection)c).removeAllAttributes() | changed;
+				}
+			}
+			if (changed) {
+				this.cache.clear();
+				this.names = null;
+				fireAttributeChange(new AttributeChangeEvent(this, Type.REMOVE_ALL, null, null, null, null));
+			}		
+			return changed;
+		}
+		finally {
+			this.runProviderEvents.set(b);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean removeAttribute(String name) {
+		boolean b = this.runProviderEvents.getAndSet(false);
+		try {
+			boolean changed = false;
+			ManyValueAttributeValue oldValue = new ManyValueAttributeValue();
+			for(AttributeProvider c : containers()) {
+				assign(oldValue, c.getAttribute(name));
+				if (c instanceof AttributeCollection) {
+					changed = ((AttributeCollection)c).removeAttribute(name) | changed;
+				}
+			}
+			if (changed) {
+				AttributeValue value = canonize(oldValue);
+				this.cache.remove(name);
+				if (this.names!=null) {
+					this.names.remove(name);
+					if (this.names.isEmpty()) this.names = null;
+				}
+				fireAttributeChange(new AttributeChangeEvent(this, Type.REMOVAL, name, value, null, null));
+			}
+			return changed;
+		}
+		finally {
+			this.runProviderEvents.set(b);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean renameAttribute(String oldname, String newname) {
+		boolean b = this.runProviderEvents.getAndSet(false);
+		try {
+			boolean changed = false;
+			ManyValueAttributeValue currentValue = new ManyValueAttributeValue();
+			for(AttributeProvider c : containers()) {
+				assign(currentValue, c.getAttribute(oldname));
+				if (c instanceof AttributeCollection) {
+					changed = ((AttributeCollection)c).renameAttribute(oldname, newname) | changed;
+				}
+			}
+			if (changed) {
+				AttributeValue cValue = canonize(currentValue);
+				this.cache.remove(oldname);
+				this.cache.remove(newname);
+				if (this.names!=null) {
+					this.names.remove(oldname);
+					this.names.add(newname);
+				}
+				fireAttributeChange(new AttributeChangeEvent(this, Type.RENAME, oldname, cValue, newname, cValue));
+			}
+			return changed;
+		}
+		finally {
+			this.runProviderEvents.set(b);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean renameAttribute(String oldname, String newname, boolean overwrite) {
+		boolean b = this.runProviderEvents.getAndSet(false);
+		try {
+			boolean changed = false;
+			ManyValueAttributeValue currentValue = new ManyValueAttributeValue();
+			for(AttributeProvider c : containers()) {
+				assign(currentValue, c.getAttribute(oldname));
+				if (c instanceof AttributeCollection) {
+					changed = ((AttributeCollection)c).renameAttribute(oldname, newname, overwrite) | changed;
+				}
+			}
+			if (changed) {
+				AttributeValue cValue = canonize(currentValue);
+				this.cache.remove(oldname);
+				if (this.names!=null) {
+					this.names.remove(oldname);
+					this.names.add(newname);
+				}
+				fireAttributeChange(new AttributeChangeEvent(this, Type.RENAME, oldname, cValue, newname, cValue));
+			}
+			return changed;
+		}
+		finally {
+			this.runProviderEvents.set(b);
+		}
+	}
+	
+	@Override
+	public void addAttributes(AttributeProvider content)
+			throws AttributeException {
+		for(Attribute attr : content.attributes()) {
+			setAttribute(attr);
+		}
+	}
+	
+	@Override
+	public void addAttributes(Map<String, Object> content) {
+		AttributeType type;
+		Object rawValue;
+		for(Entry<String,Object> entry : content.entrySet()) {
+			rawValue = entry.getValue();
+			type = AttributeType.fromValue(rawValue);
+			rawValue = type.cast(rawValue);
+			try {
+				setAttribute(entry.getKey(), new AttributeValueImpl(type, rawValue));
+			}
+			catch (AttributeException _) {
+				// should never occur
+			}
+		}
+	}
+	
+	@Override
+	public void setAttributes(AttributeProvider content)
+			throws AttributeException {
+		removeAllAttributes();
+		for(Attribute attr : content.attributes()) {
+			setAttribute(attr);
+		}
+	}
+	
+	@Override
+	public void setAttributes(Map<String, Object> content) {
+		removeAllAttributes();
+		AttributeType type;
+		Object value;
+		for(Entry<String,Object> entry : content.entrySet()) {
+			value = entry.getValue();
+			type = AttributeType.fromValue(value);
+			value = type.cast(value);
+			try {
+				setAttribute(entry.getKey(), new AttributeValueImpl(type, value));
+			}
+			catch (AttributeException e) {
+				throw new AttributeError(e);
+			}
+		}
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, AttributeValue value) throws AttributeException {
+		boolean b = this.runProviderEvents.getAndSet(false);
+		try {
+			boolean changed = false;
+			Attribute attr;
+			ManyValueAttributeValue oldValue = new ManyValueAttributeValue();
+			ManyValueAttributeValue newValue = new ManyValueAttributeValue();
+			for(AttributeProvider c : containers()) {
+				assign(oldValue, c.getAttribute(name));
+				if (c instanceof AttributeCollection) {
+					attr = ((AttributeCollection)c).setAttribute(name, value);
+					assign(newValue, attr);
+					if (attr!=null) changed = true;
+				}
+				else {
+					assign(newValue, null);
+				}
+			}
+			if (changed) {
+				AttributeValue oValue = canonize(oldValue);
+				AttributeValue nValue = canonize(newValue);
+				this.cache.put(name, nValue);
+				AttributeChangeEvent event;
+				if (nValue==null) {
+					event = new AttributeChangeEvent(this, Type.REMOVAL, name, oValue, null, null);
+				}
+				else if (oValue!=null && oValue.isAssigned()) {
+					event = new AttributeChangeEvent(this, Type.VALUE_UPDATE, name, oValue, name, nValue);
+				}
+				else {
+					event = new AttributeChangeEvent(this, Type.ADDITION, null, null, name, nValue);
+				}
+				fireAttributeChange(event);
+				return new AttributeImpl(name, value);
+			}
+			return null;
+		}
+		finally {
+			this.runProviderEvents.set(b);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, boolean value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, int value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, long value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, float value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, double value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, String value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, InetAddress value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, InetSocketAddress value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Enum<?> value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Class<?> value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, UUID value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, URL value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, URI value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Image value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Date value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(String name, Color value) {
+		try {
+			return setAttribute(name, new AttributeValueImpl(value));
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttribute(Attribute value) throws AttributeException {
+		if (value==null) return null;
+		try {
+			return setAttribute(value.getName(), value);
+		}
+		catch (AttributeException _) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute setAttributeType(String name, AttributeType type) throws AttributeException {
+		boolean b = this.runProviderEvents.getAndSet(false);
+		try {
+			ManyValueAttributeValue oldValue = new ManyValueAttributeValue();
+			ManyValueAttributeValue attr = new ManyValueAttributeValue();
+			Attribute a;
+			boolean changed = false;
+			for(AttributeProvider c : containers()) {
+				assign(oldValue, c.getAttribute(name));
+				if (c instanceof AttributeCollection) {
+					a = ((AttributeCollection)c).setAttributeType(name, type);
+					assign(attr, a);
+					if (a!=null) changed = true;
+				}
+			}
+			AttributeValue cValue = canonize(attr);
+			if (changed) {
+				AttributeValue oValue = canonize(oldValue);
+				this.cache.put(name, cValue);
+				fireAttributeChange(new AttributeChangeEvent(this, Type.VALUE_UPDATE, name, oValue, name, cValue));
+			}
+			return new AttributeImpl(name, cValue);
+		}
+		finally {
+			this.runProviderEvents.set(b);
+		}
+	}
+
+	/**
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 * @since 4.0
+	 */
+	private class Handler implements AttributeChangeListener {
+
+		/**
+		 */
+		public Handler() {
+			//
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public void onAttributeChangeEvent(AttributeChangeEvent event) {
+			if (MultiAttributeCollection.this.runProviderEvents.get()) {
+				switch(event.getType()) {
+				case ADDITION:
+					MultiAttributeCollection.this.cache.remove(event.getName());
+					if (MultiAttributeCollection.this.names!=null)
+						MultiAttributeCollection.this.names.add(event.getName());
+					break;
+				case REMOVAL:
+					MultiAttributeCollection.this.cache.remove(event.getOldName());
+					if (MultiAttributeCollection.this.names!=null)
+						MultiAttributeCollection.this.names.remove(event.getOldName());
+					break;
+				case REMOVE_ALL:
+					freeMemory();
+					break;
+				case RENAME:
+					MultiAttributeCollection.this.cache.remove(event.getOldName());
+					MultiAttributeCollection.this.cache.remove(event.getName());
+					if (MultiAttributeCollection.this.names!=null) {
+						MultiAttributeCollection.this.names.remove(event.getOldName());
+						MultiAttributeCollection.this.names.remove(event.getName());
+					}
+					break;
+				case VALUE_UPDATE:
+					MultiAttributeCollection.this.cache.remove(event.getName());
+					break;
+				default:
+				}
+			}
+		}
+
+	}
+
+}
+

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/MultiAttributeProvider.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/MultiAttributeProvider.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/MultiAttributeProvider.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,400 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Map.Entry;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.util.ref.SoftValueTreeMap;
+
+/**
+ * This class contains a collection of attribute containers and
+ * tries to gather the data.
+ * This class contains a collection of AttributeContainers and
+ * exhibites the values of the attributes of all these containers.
+ * This class follows the following rules (in that order)
+ * to retreive the value of an attribute:<ol>
+ * <li>If the attribute is defined in none of the containers, throws the standard exception;</li>
+ * <li>If the attribute is defined in only one of the containers, replies the attribute value itself;</li>
+ * <li>If the attribute is defined in more than one container:<ol>
+ * 		<li>if all the values are equal, then replies one of the attribute values;</li>
+ * 		<li>if the values are not equal and all the values have equivalent types (as replied
+ * 			by {@link AttributeType#isAssignableFrom(AttributeType)}), then replies an
+ * 			attribute value with a "undefined" value and of the type of one of the values;</li>
+ * 		<li>if the values are not equal and one of the value has not an equivalent type to
+ * 			the others (as replied by {@link AttributeType#isAssignableFrom(AttributeType)}),
+ * 			then replies an attribute value with a "undefined" value and of the type OBJECT.</li>
+ * 		</ol></li>
+ * </ol>
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 4.0
+ */
+public class MultiAttributeProvider extends AbstractAttributeProvider {
+
+	/** Cache of the attribute values.
+	 */
+	transient Map<String,AttributeValue> cache = new SoftValueTreeMap<String,AttributeValue>();
+
+	/** Cache of the names of the attributes.
+	 */
+	Set<String> names = null;
+
+	private Collection<AttributeProvider> containers = new ArrayList<AttributeProvider>();
+	
+	@Override
+	public void toMap(Map<String, Object> mapToFill) {
+		for(AttributeProvider provider : this.containers) {
+			mapToFill.putAll(provider.toMap());
+		}
+	}
+	
+	/** Replies the value associated to the specified name.
+	 */
+	private Attribute extract(String name) {
+		AttributeValue value = null;
+		if (this.cache.containsKey(name)) {
+			value = this.cache.get(name);
+		}
+		else {
+			ManyValueAttributeValue result = new ManyValueAttributeValue();
+			AttributeValue attrValue;
+			for(AttributeProvider c : this.containers) {
+				attrValue = c.getAttribute(name);
+				assign(result, attrValue);
+			}
+			value = canonize(result);
+			this.cache.put(name, value);
+		}
+		return (value!=null) ? new AttributeImpl(name, value) : null;
+	}
+
+	/** Assign the value v2 to v1 and change v1 according
+	 * to the types of v1 and v2.
+	 * Do not forget to invoke {@link #canonize(ManyValueAttributeValue)} on
+	 * <var>v1</var>.
+	 * 
+	 * @param v1
+	 * @param v2
+	 */
+	static void assign(ManyValueAttributeValue v1, AttributeValue v2) {
+		if (v2!=null) v1.setTopType(v2.getType());
+		if (v2==null || !v2.isAssigned()) {
+			v1.setMultipleValues(true);
+		}
+		else {
+			assert(v2.isAssigned());
+			if (!v1.isAssigned()) {
+				v1.setValue(v2);
+			}
+			else if (!v2.equals(v1)) {
+				v1.setMultipleValues(true);
+				if (!v1.isAssignableFrom(v2)) {
+					if (!v2.isAssignableFrom(v1))
+						v1.setInternalValue(null, AttributeType.OBJECT);
+					else
+						v1.setInternalValue(null, v2.getType());
+				}
+			}
+		}
+	}
+	
+	/** Replace any indicator put by {@link #assign(ManyValueAttributeValue, AttributeValue)}
+	 * to retreive a standard attribute value.
+	 * 
+	 * @param v is the value to canonize.
+	 * @return the canonized value.
+	 */
+	static AttributeValue canonize(ManyValueAttributeValue v) {
+		AttributeValueImpl attr;
+		if (v.hasMultipleValues()) {
+			if (v.getTopType()==null) return null;
+			attr = new AttributeValueImpl(v.getTopType(), null);
+		}
+		else {
+			attr = new AttributeValueImpl();
+			attr.setValue(v);
+		}
+		return attr;
+	}
+
+	/** Replies a collection on the containers.
+	 * 
+	 * @return a collection on the containers.
+	 */
+	protected Collection<AttributeProvider> containers() {
+		return Collections.unmodifiableCollection(this.containers);
+	}
+
+	/** Add a container in this set.
+	 * 
+	 * @param container
+	 * @return <code>true</code> if the container has been added,
+	 *  otherwise <code>false</code> 
+	 */
+	public boolean addAttributeContainer(AttributeProvider container) {
+		if (this.containers.add(container)) {
+			freeMemory();
+			return true;
+		}
+		return false;
+	}
+
+	/** Remove a container in this set.
+	 * 
+	 * @param container 
+	 * @return <code>true</code> if the container has been removed,
+	 *  otherwise <code>false</code> 
+	 */
+	public boolean removeAttributeContainer(AttributeProvider container) {
+		if (this.containers.remove(container)) {
+			freeMemory();
+			return true;
+		}
+		return false;
+	}
+	
+	/** Replies the number of attribute containers in this MultiAttributeContainer.
+	 * 
+	 * @return the number of attribute containers in this MultiAttributeContainer.
+	 */
+	public int getAttributeContainerCount() {
+		return this.containers.size();
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public MultiAttributeProvider clone() {
+		MultiAttributeProvider clone = (MultiAttributeProvider)super.clone();
+		clone.cache = new SoftValueTreeMap<String,AttributeValue>();
+		for(Entry<String,AttributeValue> e : this.cache.entrySet()) {
+			clone.cache.put(e.getKey(), new AttributeValueImpl(e.getValue()));
+		}
+		clone.containers = new ArrayList<AttributeProvider>(this.containers);
+		if (this.names!=null) {
+			clone.names = new TreeSet<String>(new AttributeNameStringComparator());
+			clone.names.addAll(this.names);
+		}
+		return clone;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void freeMemory() {
+		this.cache.clear();
+		if (this.names!=null) this.names.clear();
+		this.names = null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Collection<Attribute> getAllAttributes() {
+		ArrayList<Attribute> list = new ArrayList<Attribute>(getAttributeCount());
+		Attribute newAttr;
+		for(String name : getAllAttributeNames()) {
+			if (name!=null) {
+				newAttr = extract(name);
+				if (newAttr!=null) list.add(newAttr);
+			}
+		}
+		return list;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<AttributeType, Collection<Attribute>> getAllAttributesByType() {
+		TreeMap<AttributeType,Collection<Attribute>> map = new TreeMap<AttributeType,Collection<Attribute>>();
+		Attribute newAttr;
+		for(String name : getAllAttributeNames()) {
+			if (name!=null) {
+				newAttr = extract(name);
+				if (newAttr!=null) {
+					Collection<Attribute> list = map.get(newAttr.getType());
+					if (list==null) {
+						list = new ArrayList<Attribute>();
+						map.put(newAttr.getType(), list);
+					}
+					list.add(newAttr);
+				}
+			}
+		}
+		return map;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public AttributeValue getAttribute(String name) {
+		return extract(name);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public AttributeValue getAttribute(String name, AttributeValue defaultValue) {
+		AttributeValue value = extract(name);
+		if (value==null) value = defaultValue;
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int getAttributeCount() {
+		return getAllAttributeNames().size();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Collection<String> getAllAttributeNames() {
+		if (this.names==null) {
+			Set<String> names = new TreeSet<String>(new AttributeNameStringComparator());
+			for(AttributeProvider c : this.containers) {
+				names.addAll(c.getAllAttributeNames());
+			}
+			this.names = names;
+		}
+		return Collections.unmodifiableSet(this.names);
+	}
+
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute getAttributeObject(String name) {
+		return extract(name);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean hasAttribute(String name) {
+		for(AttributeProvider c : this.containers) {
+			if (c.hasAttribute(name)) return true;
+		}
+		return false;
+	}
+
+	/** This class provides an implementation of attribute value
+	 * that may be marked with an indicators that many
+	 * values are possibles for the attribute.
+	 * 
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 * @since 4.0
+	 */
+	static class ManyValueAttributeValue extends AttributeValueImpl {
+
+		private boolean hasMultipleValues = false;
+		private AttributeType topType = null;
+		
+		/** Replies the type type associated to this attribute value.
+		 * 
+		 * @return the top type associated to this attribute value.
+		 */
+		public AttributeType getTopType() {
+			return this.topType;
+		}
+		
+		/** Set the top type associated to this attribute value.
+		 * 
+		 * @param type is the top type associated to this attribute value.
+		 */
+		public void setTopType(AttributeType type) {
+			if (this.topType==null) {
+				this.topType = type;
+			}
+			else if (this.topType!=type) {
+				if (!this.topType.isAssignableFrom(type)) {
+					if (type.isAssignableFrom(this.topType)) {
+						this.topType = type;
+					}
+					else {
+						this.topType = AttributeType.OBJECT;
+					}
+				}
+			}
+		}
+		
+		@Override
+		public final void setInternalValue(Object value) {
+			super.setInternalValue(value);
+		}
+		
+		@Override
+		public final void setInternalValue(Object value, AttributeType type) {
+			super.setInternalValue(value, type);
+		}
+
+		/** Replies if this attribute has multiple values.
+		 * 
+		 * @return <code>true</code> if this attribute has multiple
+		 * values, otherwise <code>false</code>.
+		 */
+		public boolean hasMultipleValues() {
+			return this.hasMultipleValues;
+		}
+		
+		/** Set if this attribute has multiple values.
+		 * 
+		 * @param v is <code>true</code> if this attribute has multiple
+		 * values, otherwise <code>false</code>.
+		 */
+		public void setMultipleValues(boolean v) {
+			this.hasMultipleValues = v;
+		}
+
+	}
+	
+}
+

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/NoAttributeFoundException.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/NoAttributeFoundException.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/NoAttributeFoundException.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,60 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import org.arakhne.afc.attrs.attr.AttributeException;
+
+/**
+ * This exception is generated each time an attribute
+ * was not found.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class NoAttributeFoundException extends AttributeException {
+	
+	private static final long serialVersionUID = 6988928120286302957L;
+
+	/**
+	 */
+	public NoAttributeFoundException() {
+		super();
+	}
+
+	/**
+	 * @param attrname is the name of the not-found attribute.
+	 */
+	public NoAttributeFoundException(String attrname) {
+		super(attrname);
+	}
+
+	/**
+	 * @param e is the exception to forward
+	 */
+	public NoAttributeFoundException(Exception e) {
+		super(e);
+	}
+
+}
\ No newline at end of file

Added: trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/ROMBasedAttributeCollection.java
===================================================================
--- trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/ROMBasedAttributeCollection.java	                        (rev 0)
+++ trunk/attrs/src/main/java/org/arakhne/afc/attrs/collection/ROMBasedAttributeCollection.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,72 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.Collection;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+
+/**
+ * This interface representes a provider of attributes that is
+ * partly based on data stored on a ROM (read-only memory).
+ * <p>
+ * The changed values are stored inside the memory and never
+ * written back into the ROM.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface ROMBasedAttributeCollection extends AttributeCollection { 
+
+	/** Replies the list of attributes that have
+	 * changed.
+	 * 
+	 * @return the list of the names of the attributes which are stored inside the memory buffer.
+	 */
+	public Collection<String> getAllBufferedAttributeNames();
+
+	/** Replies the list of attributes that have
+	 * changed.
+	 * 
+	 * @return the list of attributes stored inside the memory buffer.
+	 */
+	public Collection<Attribute> getAllBufferedAttributes();
+
+	/** Replies if the specified attribute name corresponds to
+	 * a buffered attribute value.
+	 * 
+	 * @param attributeName
+	 * @return <code>true</code> if an attribute with the given name
+	 * is stored inside the memory buffer, otherwise <code>false</code>
+	 */
+	public boolean isBufferedAttribute(String attributeName);
+
+	/** Replies the count of buffered attributes.
+	 * 
+	 * @return the count of buffered attributes.
+	 */
+	public int getBufferedAttributeCount();
+
+}

Added: trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types.properties
===================================================================
--- trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types.properties	                        (rev 0)
+++ trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types.properties	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,41 @@
+# $Id$
+# 
+# Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+#                        Universite de Technologie de Belfort-Montbeliard.
+# Copyright (C) 2013 Stephane GALLAND.
+# 
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+# This program is free software; you can redistribute it and/or modify
+
+BOOLEAN = Boolean
+COLOR = Color
+DATE = Date
+ENUMERATION = Enumeration
+FLOAT = Float
+ICON = Icon
+INET_ADDRESS = Internet Address
+INTEGER = Integer
+OBJECT = Object
+OTHER = Other
+POINT2D = Point 2d
+POINT3D = Point 3d
+POLYLINE = Polyline 2d
+POLYLINE3D = Polyline 3d
+STRING = String
+TIMESTAMP = Timestamp
+TYPE = Java Type
+UUID = Unique Universal Identifier
+URI = Uniform resource identifier
+URL = Uniform resource locator
\ No newline at end of file

Added: trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types_es.properties
===================================================================
--- trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types_es.properties	                        (rev 0)
+++ trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types_es.properties	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,41 @@
+# $Id$
+# 
+# Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+#                        Universite de Technologie de Belfort-Montbeliard.
+# Copyright (C) 2013 Stephane GALLAND.
+# 
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+# This program is free software; you can redistribute it and/or modify
+
+BOOLEAN = Booleano
+COLOR = Color
+DATE = Fecha
+ENUMERATION = Enumeraci\xF3n
+FLOAT = N\xFAmero decimal
+ICON = Icono
+INET_ADDRESS = N\xFAmero Internet
+INTEGER = N\xFAmero entero
+OBJECT = Asunto
+OTHER = Otro
+POINT2D = Punto 2d
+POINT3D = Punto 3d
+POLYLINE = Poly-l\xEDnea 2d
+POLYLINE3D = Poly-l\xEDnea 3d
+STRING = Cadena de caracteres
+TIMESTAMP = Estampilla
+TYPE = Tipo Java
+UUID = Identificaci\xF3n \xFAnico universal
+URI = Identificador uniforme de recursos
+URL = Localizador de recurso uniforme
\ No newline at end of file

Added: trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types_fr.properties
===================================================================
--- trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types_fr.properties	                        (rev 0)
+++ trunk/attrs/src/main/resources/org/arakhne/afc/attrs/types_fr.properties	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,41 @@
+# $Id$
+# 
+# Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+#                        Universite de Technologie de Belfort-Montbeliard.
+# Copyright (C) 2013 Stephane GALLAND.
+# 
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# 
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+# This program is free software; you can redistribute it and/or modify
+
+BOOLEAN = Bool\xE9en
+COLOR = Couleur
+DATE = Date
+ENUMERATION = Enumeration
+FLOAT = Nombre d\xE9cimal
+ICON = Ic\xF4ne
+INET_ADDRESS = Addresse Internet
+INTEGER = Nombre entier
+OBJECT = Objet
+OTHER = Autre
+POINT2D = Point 2d
+POINT3D = Point 3d
+POLYLINE = Poly-ligne 2d
+POLYLINE3D = Poly-ligne 3d
+STRING = Cha\xEEne de caract\xE8res
+TIMESTAMP = Estampille
+TYPE = Type Java
+UUID = Identification universel unique
+URI = Identificateur uniforme de ressource
+URL = Adresse uniforme de ressource
\ No newline at end of file

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/AbstractAttrTestCase.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/AbstractAttrTestCase.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/AbstractAttrTestCase.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,434 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Random;
+import java.util.UUID;
+
+import junit.framework.TestCase;
+
+/**
+ * Test of Attribute.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AbstractAttrTestCase extends TestCase {
+
+	/**
+	 */
+	protected final Random RANDOM = new Random();
+	
+	/**
+	 * @param message is the message to format
+	 * @param expected is the expected value
+	 * @param actual is the current value
+	 * @return the formated message
+	 */
+	static String formatMsg(String message, Object expected, Object actual) {
+		String formatted= ""; //$NON-NLS-1$
+		if (message != null)
+			formatted= message+" "; //$NON-NLS-1$
+		return formatted+"expected:<"+expected+"> but was:<"+actual+">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+	}
+	
+	/** Create a string.
+	 * @return a string
+	 */
+	protected static String randomString() {
+		return UUID.randomUUID().toString();
+	}
+	
+	/** Random a value from an enumeration.
+	 * 
+	 * @param <E> is the type of the enumeration
+	 * @param type is the type of the enumeration
+	 * @return a value from the specified enumeration.
+	 */
+	protected <E extends Enum<E>> E randomEnum(Class<E> type) {
+		E[] constants = type.getEnumConstants();
+		return constants[this.RANDOM.nextInt(constants.length)];
+	}
+	
+	/** Test if the two date are equals with an epsilon.
+	 * 
+	 * @param expected
+	 * @param actual
+	 */
+	protected static void assertEpsilonEquals(Date expected, Date actual) {
+		if (expected == null && actual == null) return;
+		String message = null;
+		if (expected!=null) {
+			DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");   //$NON-NLS-1$
+			String expectedStr = fmt.format(expected);
+			String actualStr = fmt.format(expected);
+			if (expectedStr.equals(actualStr)) return;
+			message = "expected <"+expectedStr+">, actual: <"+actualStr+">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		}
+		fail(formatMsg(message, expected, actual));
+	}
+	
+	/** Test if the two collections contain the same elements and
+	 * taking into account the order of the elements in the collections.
+	 *
+	 * @param <T>
+	 * @param expected
+	 * @param actual
+	 */
+	protected static <T> void assertEquals(T[] expected, T[] actual) {
+		assertEquals(null, expected, actual);
+	}
+	
+	/** Test if the two collections contain the same elements and
+	 * taking into account the order of the elements in the collections.
+	 *
+	 * @param <T>
+	 * @param message
+	 * @param expected
+	 * @param actual
+	 */
+	protected static <T> void assertEquals(String message, T[] expected, T[] actual) {
+		if (actual==expected) return;
+		if (actual==null) {
+			fail(formatMsg((message==null ? "" : (message+": "))  //$NON-NLS-1$//$NON-NLS-2$
+					+"not same arrays, not same size",//$NON-NLS-1$
+					expected.length, 0));
+		}
+		else {
+			if (expected==null) {
+				fail(formatMsg((message==null ? "" : (message+": "))  //$NON-NLS-1$//$NON-NLS-2$
+						+"not same arrays, not same size",//$NON-NLS-1$
+						0, actual.length));
+			}
+			else {
+				if (actual.length!=expected.length) {
+					fail(formatMsg((message==null ? "" : (message+": "))  //$NON-NLS-1$//$NON-NLS-2$
+							+"not same arrays, not same size",//$NON-NLS-1$
+							expected.length, actual.length));
+				}
+				T o1, o2;
+				for(int i=0; i<expected.length; i++) {
+					o1 = expected[i];
+					o2 = actual[i];
+					if ((o1!=o2)&&
+						((o1==null)||(o2==null)||
+						 (!o1.equals(o2)))) {
+						fail(formatMsg((message==null ? "" : (message+": "))  //$NON-NLS-1$//$NON-NLS-2$
+								+"not same arrays, expected element:", //$NON-NLS-1$
+								o1, o2));
+					}
+				}
+			}
+		}
+	}	
+
+	/** Test if the given method entity throws the specified exception on the given entity.
+	 * 
+	 * @param expectedException
+	 * @param object
+	 * @param methodName
+	 * @param values are the values to pass to the methods.
+	 */
+	protected static void assertException(Class<? extends Throwable> expectedException,
+			Object object, String methodName, Object... values) {
+		assertException(null, expectedException, object, methodName, values);
+	}
+
+	/** Test if the given method entity throws the specified exception on the given entity.
+	 * 
+	 * @param message
+	 * @param expectedException
+	 * @param object
+	 * @param methodName
+	 * @param values are the values to pass to the methods.
+	 */
+	protected static void assertException(String message, Class<? extends Throwable> expectedException,
+			Object object, String methodName, Object... values) {
+		Class<?>[] types = new Class<?>[values.length];
+		for(int idx=0; idx<types.length; idx++) {
+			types[idx] = values[idx].getClass();
+		}
+		assertException(message, expectedException, object, methodName, types, values);
+	}
+
+	/** Test if the given method entity throws the specified exception on the given entity.
+	 * 
+	 * @param expectedException
+	 * @param object
+	 * @param methodName
+	 * @param types are the types of the method parameters.
+	 * @param values are the values to pass to the methods.
+	 */
+	protected static void assertException(Class<? extends Throwable> expectedException,
+			Object object, String methodName, Class<?>[] types, Object... values) {
+		assertException(null, expectedException, object, methodName, types, values);
+	}
+
+	/** Test if the given method entity throws the specified exception on the given entity.
+	 * 
+	 * @param message
+	 * @param expectedException
+	 * @param object
+	 * @param methodName
+	 * @param types are the types of the method parameters.
+	 * @param values are the values to pass to the methods.
+	 */
+	protected static void assertException(String message, Class<? extends Throwable> expectedException,
+			Object object, String methodName, Class<?>[] types, Object... values) {
+		assert(object!=null);
+		Class<?> objType;
+		Object obj = object;
+		if (obj instanceof Class<?>) {
+			objType = (Class<?>)obj;
+			obj = null;
+		}
+		else {
+			objType = obj.getClass();
+		}
+		Method method = null;
+		Throwable t = null;
+		try {
+			method = objType.getMethod(methodName, types);
+			if (method==null) {
+				fail((message!=null?(message+", ") //$NON-NLS-1$
+						:"") //$NON-NLS-1$
+						+"unable to find the method "+methodName); //$NON-NLS-1$
+				return;
+			}
+		}
+		catch(Exception _) {
+			fail((message!=null?(message+", ") //$NON-NLS-1$
+					:"") //$NON-NLS-1$
+					+"unable to find the method "+methodName); //$NON-NLS-1$
+			return;
+		}
+		try {
+			method.invoke(obj, values);
+		}
+		catch(InvocationTargetException e) {
+			if (expectedException.equals(e.getCause().getClass())) return;
+			t = e.getCause();
+		}
+		catch(Throwable e) {
+			if (expectedException.equals(e.getClass())) return;
+			t = e;
+		}
+		if (t!=null) {
+			fail((message!=null?(message+", ") //$NON-NLS-1$
+					:"") //$NON-NLS-1$
+					+"the method "+methodName //$NON-NLS-1$
+					+" does not thrown the expected exception of type "+expectedException //$NON-NLS-1$
+					+". An exception of type "+t.getClass().getName()+" is thrown insteed."); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		else {
+			fail((message!=null?(message+", ") //$NON-NLS-1$
+					:"") //$NON-NLS-1$
+					+"the method "+methodName //$NON-NLS-1$
+					+" does not thrown the expected exception of type "+expectedException //$NON-NLS-1$
+					+". No exception was thrown insteed."); //$NON-NLS-1$
+		}
+	}
+
+	/** Test if the value is strictly negative.
+	 * 
+	 * @param value
+	 */
+	protected static void assertStrictlyNegative(double value) {
+		assertStrictlyNegative(null, value);
+	}
+
+	/** Test if the value is strictly negative.
+	 * 
+	 * @param message
+	 * @param value
+	 */
+	protected static void assertStrictlyNegative(String message, double value) {
+		if (value>=0) {
+			StringBuilder msg = new StringBuilder();
+			if (message!=null) msg.append(message);
+			if (msg.length()>0) msg.append(' ');
+			msg.append("the value is expected to be stricly negative, but it is equals to "); //$NON-NLS-1$
+			msg.append(value);
+			fail(msg.toString());
+		}
+	}
+	
+	/** Test if the value is strictly positive.
+	 * 
+	 * @param value
+	 */
+	protected static void assertStrictlyPositive(double value) {
+		assertStrictlyPositive(null, value);
+	}
+
+	/** Test if the value is strictly positive.
+	 * 
+	 * @param message
+	 * @param value
+	 */
+	protected static void assertStrictlyPositive(String message, double value) {
+		if (value<=0) {
+			StringBuilder msg = new StringBuilder();
+			if (message!=null) msg.append(message);
+			if (msg.length()>0) msg.append(' ');
+			msg.append("the value is expected to be stricly positive, but it is equals to "); //$NON-NLS-1$
+			msg.append(value);
+			fail(msg.toString());
+		}
+	}
+
+	/** Test if the value is negative or zero.
+	 * 
+	 * @param value
+	 */
+	protected static void assertNegative(double value) {
+		assertNegative(null, value);
+	}
+
+	/** Test if the value is negative or zero.
+	 * 
+	 * @param message
+	 * @param value
+	 */
+	protected static void assertNegative(String message, double value) {
+		if (value>0) {
+			StringBuilder msg = new StringBuilder();
+			if (message!=null) msg.append(message);
+			if (msg.length()>0) msg.append(' ');
+			msg.append("the value is expected to be negative or nul, but it is equals to "); //$NON-NLS-1$
+			msg.append(value);
+			fail(msg.toString());
+		}
+	}
+	
+	/** Test if the value is positive or zero.
+	 * 
+	 * @param value
+	 */
+	protected static void assertPositive(double value) {
+		assertPositive(null, value);
+	}
+
+	/** Test if the value is positive or zero.
+	 * 
+	 * @param message
+	 * @param value
+	 */
+	protected static void assertPositive(String message, double value) {
+		if (value<0) {
+			StringBuilder msg = new StringBuilder();
+			if (message!=null) msg.append(message);
+			if (msg.length()>0) msg.append(' ');
+			msg.append("the value is expected to be positive or nul, but it is equals to "); //$NON-NLS-1$
+			msg.append(value);
+			fail(msg.toString());
+		}
+	}
+
+	/** Test if the two collections contain the same elements without
+	 * taking into account the order of the elements in the collections.
+	 *
+	 * @param <T>
+	 * @param expected
+	 * @param actual
+	 */
+	protected static <T> void assertEpsilonEquals(T[] expected, T[] actual) {
+		assertEpsilonEquals(null, expected, actual);
+	}
+
+	/** Test if the two collections contain the same elements without
+	 * taking into account the order of the elements in the collections.
+	 *
+	 * @param <T>
+	 * @param message
+	 * @param expected
+	 * @param actual
+	 */
+	protected static <T> void assertEpsilonEquals(String message, T[] expected, T[] actual) {
+		ArrayList<T> l = new ArrayList<T>(Arrays.asList(actual));
+		for(T e : expected) {
+			if (!l.remove(e)) {
+				fail((message==null ? "" : (message+": "))  //$NON-NLS-1$//$NON-NLS-2$
+						+"not similar collections, expected element:"+ //$NON-NLS-1$
+						expected.toString());
+			}
+		}
+		if (!l.isEmpty()) {
+			fail((message==null ? "" : (message+": "))  //$NON-NLS-1$//$NON-NLS-2$
+					+"not similar collections, not expected elements:"+ //$NON-NLS-1$
+					l.toString());
+		}
+	}
+
+	/** Test if the two collections contain the same elements without
+	 * taking into account the order of the elements in the collections.
+	 * 
+	 * @param <T>
+	 * @param expected
+	 * @param actual
+	 */
+	protected static <T> void assertEpsilonEquals(Collection<? extends T> expected, Collection<? extends T> actual) {
+		assertEpsilonEquals(null, expected, actual);
+	}
+
+	/** Test if the two collections contain the same elements without
+	 * taking into account the order of the elements in the collections.
+	 *
+	 * @param <T>
+	 * @param message
+	 * @param expected
+	 * @param actual
+	 */
+	protected static <T> void assertEpsilonEquals(String message, Collection<? extends T> expected, Collection<? extends T> actual) {
+		ArrayList<T> l = new ArrayList<T>(actual);
+		for(T e : expected) {
+			if (!l.remove(e)) {
+				fail((message==null ? "" : (message+": "))  //$NON-NLS-1$//$NON-NLS-2$
+						+"not similar collections, expected element:"+ //$NON-NLS-1$
+						expected);
+			}
+		}
+		if (!l.isEmpty()) {
+			fail((message==null ? "" : (message+": "))  //$NON-NLS-1$//$NON-NLS-2$
+					+"not similar collections, not expected elements:"+ //$NON-NLS-1$
+					l);
+		}
+	}
+
+	/**
+	 */
+	public void testIddle() {
+		//
+	}	
+
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeComparatorTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeComparatorTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeComparatorTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,147 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import org.arakhne.afc.attrs.AbstractAttrTestCase;
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeComparator;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+
+/**
+ * Test of AttributeComparator.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeComparatorTest extends AbstractAttrTestCase {
+
+	/**
+	 * @throws AttributeException
+	 */
+	public static void testCompareValues() throws AttributeException {
+		double base_d = Math.random();
+		long base_l = (long)base_d;
+		AttributeValueImpl attr1 = new AttributeValueImpl(base_d);		
+		AttributeValueImpl attr2 = new AttributeValueImpl(base_d+1);
+		AttributeValueImpl attr3 = new AttributeValueImpl(base_d-1);
+		
+		AttributeValueImpl attr4 = new AttributeValueImpl(base_l);		
+		AttributeValueImpl attr5 = new AttributeValueImpl(attr1.getInteger());
+		
+		AttributeValueImpl attr6 = new AttributeValueImpl("bonjour"); //$NON-NLS-1$
+		
+		AttributeComparator comp = new AttributeComparator();
+			
+		//----------- attr1 -> *
+		assertEquals(0, comp.compare(attr1,attr1));
+		assertStrictlyNegative(comp.compare(attr1,attr2));
+		assertStrictlyPositive(comp.compare(attr1,attr3));
+		assertPositive(comp.compare(attr1,attr4));
+		assertPositive(comp.compare(attr1,attr5));
+		assertStrictlyNegative(comp.compare(attr1,attr6));
+
+		//----------- attr2 -> *
+		assertStrictlyPositive(comp.compare(attr2,attr1));
+		assertEquals(0, comp.compare(attr2,attr2));
+		assertStrictlyPositive(comp.compare(attr2,attr3));
+		assertStrictlyPositive(comp.compare(attr2,attr4));
+		assertStrictlyPositive(comp.compare(attr2,attr5));
+		assertStrictlyNegative(comp.compare(attr2,attr6));
+
+		//----------- attr3 -> *
+		assertStrictlyNegative(comp.compare(attr3,attr1));
+		assertStrictlyNegative(comp.compare(attr3,attr2));
+		assertEquals(0, comp.compare(attr3,attr3));
+		assertStrictlyNegative(comp.compare(attr3,attr4));
+		assertStrictlyNegative(comp.compare(attr3,attr5));
+		assertStrictlyNegative(comp.compare(attr3,attr6));
+		
+
+		//----------- attr4 -> *
+		assertNegative(comp.compare(attr4,attr1));
+		assertStrictlyNegative(comp.compare(attr4,attr2));
+		assertStrictlyPositive(comp.compare(attr4,attr3));
+		assertEquals(0, comp.compare(attr4,attr4));
+		assertEquals(0,comp.compare(attr4,attr5));
+		assertStrictlyNegative(comp.compare(attr4,attr6));
+
+		//----------- attr5 -> *
+		assertNegative(comp.compare(attr5,attr1));
+		assertStrictlyNegative(comp.compare(attr5,attr2));
+		assertStrictlyPositive(comp.compare(attr5,attr3));
+		assertEquals(0,comp.compare(attr5,attr4));
+		assertEquals(0, comp.compare(attr5,attr5));
+		assertStrictlyNegative(comp.compare(attr5,attr6));
+
+		//----------- attr6 -> *
+		assertStrictlyPositive(comp.compare(attr6,attr1));
+		assertStrictlyPositive(comp.compare(attr6,attr2));
+		assertStrictlyPositive(comp.compare(attr6,attr3));
+		assertStrictlyPositive(comp.compare(attr6,attr4));
+		assertStrictlyPositive(comp.compare(attr6,attr5));
+		assertEquals(0, comp.compare(attr6,attr6));
+	}
+
+	/**
+	 */
+	public static void testCompare() {
+		AttributeComparator comp = new AttributeComparator();
+		
+		for(int i=5; i<50; ++i) {
+			String name1 = randomString();
+			String name2 = randomString();
+			String msg = "("+name1+"<=>"+name2+")";  //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+			int cmpResult = name1.compareTo(name2);
+			
+			Attribute attr1 = new AttributeImpl(name1,1);
+			Attribute attr2 = new AttributeImpl(name2,1);
+			Attribute attr3 = new AttributeImpl(name1,1);
+			Attribute attr4 = new AttributeImpl(name1,2);
+			
+			assertEquals(msg,0,comp.compare(attr1, attr1));
+			assertEquals(msg,cmpResult,comp.compare(attr1, attr2));
+			assertEquals(msg,0,comp.compare(attr1, attr3));
+			assertStrictlyNegative(msg,comp.compare(attr1, attr4));
+			
+			assertEquals(msg,-cmpResult,comp.compare(attr2, attr1));
+			assertEquals(msg,0,comp.compare(attr2, attr2));
+			assertEquals(msg,-cmpResult,comp.compare(attr2, attr3));
+			assertEquals(msg,-cmpResult,comp.compare(attr2, attr4));
+
+			assertEquals(msg,0,comp.compare(attr3, attr1));
+			assertEquals(msg,cmpResult,comp.compare(attr3, attr2));
+			assertEquals(msg,0,comp.compare(attr3, attr3));
+			assertStrictlyNegative(msg,comp.compare(attr3, attr4));
+
+			assertStrictlyPositive(msg,comp.compare(attr4, attr1));
+			assertEquals(msg,cmpResult,comp.compare(attr4, attr2));
+			assertStrictlyPositive(msg,comp.compare(attr4, attr3));
+			assertEquals(msg,0,comp.compare(attr4, attr4));
+		}
+	}
+
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,1125 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Random;
+
+import org.arakhne.afc.attrs.AbstractAttrTestCase;
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeNotInitializedException;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.attrs.attr.InvalidAttributeTypeException;
+import org.arakhne.afc.math.continous.object2d.Point2f;
+import org.arakhne.afc.math.continous.object3d.Point3f;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Point3D;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+import org.arakhne.afc.ui.vector.VectorToolkit;
+
+/**
+ * Test of Attribute.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeTest extends AbstractAttrTestCase {
+
+	/**
+	 * @param attr
+	 * @param type
+	 */
+	protected static void assertAllGetFailed(AttributeValue attr, AttributeType type) {
+		try {
+			attr.getValue();
+			fail("getValue: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getBoolean();
+			fail("getBoolean: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getColor();
+			fail("getColor: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getDate();
+			fail("getDate: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getImage();
+			fail("getImage: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getInteger();
+			fail("getInteger: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getJavaObject();
+			if (type.isBaseType())
+				fail("getJavaObject: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeNotInitializedException _) {
+			// expected case
+		}
+		catch(InvalidAttributeTypeException _) {
+			if (attr.isObjectValue())
+				fail("getJavaObject: unexpected exception InvalidAttributeTypeException for "+type); //$NON-NLS-1$
+		}
+
+		try {
+			attr.getPoint();
+			fail("getPoint: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getPoint3D();
+			fail("getPoint3D: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getPoint3D();
+			fail("getPoint3D: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getPolyline3D();
+			fail("getPolyline3D: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getReal();
+			fail("getReal: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getString();
+			fail("getString: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeNotInitializedException _) {
+			// expected case
+		}
+		catch(InvalidAttributeTypeException _) {
+			if (!attr.isObjectValue())
+				fail("getString: unexpected exception InvalidAttributeTypeException for "+type); //$NON-NLS-1$
+		}
+
+		try {
+			attr.getTimestamp();
+			fail("getTimestamp: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getURI();
+			fail("getURI: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getURL();
+			fail("getURL: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getUUID();
+			fail("getUUID: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+}
+
+	/**
+	 * @param attr
+	 * @param methodName
+	 * @throws Exception
+	 */
+	protected static void assertAttributeException(AttributeValue attr, String methodName) throws Exception {
+		try {
+			Class<? extends AttributeValue> clazz = attr.getClass();
+			Method method = clazz.getMethod(methodName);
+			method.invoke(attr);
+			fail("the exception AttributeException was not thrown"); //$NON-NLS-1$
+		}
+		catch(InvocationTargetException e) {
+			Throwable ex = e.getTargetException();
+			if (ex instanceof AttributeException) {
+				//
+			}
+			else {
+				fail("the exception AttributeException was not thrown"); //$NON-NLS-1$
+			}
+		}
+	}
+
+	
+	/**
+	 */
+	public static void testAttributeImpl() {
+		Attribute attr = new AttributeImpl();
+		
+		assertFalse(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(AttributeType.OBJECT, attr.getType());
+		
+		try {
+			attr.getValue();
+			fail("the exception AttributeNotInitializedException was not thrown"); //$NON-NLS-1$
+		}
+		catch(AttributeNotInitializedException _) {
+			// expected case
+		}
+		catch(InvalidAttributeTypeException _) {
+			fail("unexpected exception InvalidAttributeTypeException"); //$NON-NLS-1$
+		}
+
+		try {
+			attr.getBoolean();
+			fail("the exception AttributeNotInitializedException was not thrown"); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplAttributeType() throws Exception {
+		AttributeType[] values = AttributeType.values();
+		//AttributeType[] values = new AttributeType[] {AttributeType.OBJECT};
+		for (AttributeType type : values) {
+			Attribute attr = new AttributeImpl(type);
+			
+			assertEquals(type, attr.getType());
+
+			assertFalse(attr.isAssigned());
+			assertEquals(type.isBaseType(),attr.isBaseType());
+			assertEquals("on type "+type, //$NON-NLS-1$
+					!type.isBaseType(),
+					attr.isObjectValue());
+			
+			if (type.isNullAllowed()) {
+				assertAttributeException(attr, "getBoolean"); //$NON-NLS-1$
+				assertAttributeException(attr, "getColor"); //$NON-NLS-1$
+				assertAttributeException(attr, "getDate"); //$NON-NLS-1$
+				assertAttributeException(attr, "getImage"); //$NON-NLS-1$
+				assertAttributeException(attr, "getInteger"); //$NON-NLS-1$
+				assertNull(attr.getJavaObject());
+				assertAttributeException(attr, "getPoint"); //$NON-NLS-1$
+				assertAttributeException(attr, "getPoint3D"); //$NON-NLS-1$
+				assertAttributeException(attr, "getPolyline"); //$NON-NLS-1$
+				assertAttributeException(attr, "getPolyline3D"); //$NON-NLS-1$
+				assertAttributeException(attr, "getReal"); //$NON-NLS-1$
+				assertAttributeException(attr, "getString"); //$NON-NLS-1$
+				assertAttributeException(attr, "getTimestamp"); //$NON-NLS-1$
+				assertAttributeException(attr, "getURI"); //$NON-NLS-1$
+				assertAttributeException(attr, "getURL"); //$NON-NLS-1$
+				assertAttributeException(attr, "getUUID"); //$NON-NLS-1$
+				assertAttributeException(attr, "getValue"); //$NON-NLS-1$
+			}
+			else {
+				assertAllGetFailed(attr, type);
+			}
+		}
+	}
+	
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplBoolean() throws Exception {
+		Attribute attr = new AttributeImpl(randomString(),false);
+		
+		assertEquals(AttributeType.BOOLEAN, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertFalse((Boolean)attr.getValue());
+		assertFalse(attr.getBoolean());
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(0, attr.getInteger());
+		assertEquals(0., attr.getReal());
+		assertEquals(0, attr.getTimestamp());
+		assertEquals(Boolean.toString(false),attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplColor() throws Exception {
+		String txt = "255;0;0;255"; //$NON-NLS-1$
+		Attribute attr = new AttributeImpl(randomString(),VectorToolkit.RED);
+		
+		assertEquals(AttributeType.COLOR, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(VectorToolkit.RED,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.RED,attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.RED.getRGB(), attr.getInteger());
+		assertEquals((double)VectorToolkit.RED.getRGB(), attr.getReal());
+		assertEquals(VectorToolkit.RED.getRGB(), attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertEquals(VectorToolkit.color(255,0,0), attr.getJavaObject());
+		assertEquals(new Point2f(255,0),attr.getPoint());
+		assertEquals(new Point3f(255,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplDate() throws Exception {
+		Date currentDate = new Date();
+		SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
+		String txt = fmt.format(currentDate);
+		Attribute attr = new AttributeImpl(randomString(),currentDate);
+		
+		assertEquals(AttributeType.DATE, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(currentDate,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color((int)currentDate.getTime()), attr.getColor());
+		assertEquals(currentDate,attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(currentDate.getTime(),attr.getInteger());
+		assertEquals((double)currentDate.getTime(),attr.getReal());
+		assertEquals(currentDate.getTime(),attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertEquals(currentDate, attr.getJavaObject());
+		assertEquals(new Point2f(currentDate.getTime(), 0), attr.getPoint());
+		assertEquals(new Point3f(currentDate.getTime(), 0, 0), attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplFloat() throws Exception {
+		float nb = (float)Math.random();
+		String txt = Double.toString(nb);
+		Attribute attr = new AttributeImpl(randomString(),nb);
+		
+		assertEquals(AttributeType.REAL, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(nb,((Number)attr.getValue()).floatValue());
+		assertEquals(nb!=0f, attr.getBoolean());
+		assertEquals(VectorToolkit.color((int)nb), attr.getColor());
+		assertEquals(new Date((long)nb),attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals((long)nb,attr.getInteger());
+		assertEquals((double)nb,attr.getReal());
+		assertEquals((long)nb,attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2f(nb,0),attr.getPoint());
+		assertEquals(new Point3f(nb,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplDouble() throws Exception {
+		/**
+		 * @throws Exception
+		 */
+		double nb = Math.random();
+		String txt = Double.toString(nb);
+		Attribute attr = new AttributeImpl(randomString(),nb);
+		
+		assertEquals(AttributeType.REAL, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(nb,((Number)attr.getValue()).doubleValue());
+		assertEquals(nb!=0., attr.getBoolean());
+		assertEquals(VectorToolkit.color((int)nb), attr.getColor());
+		assertEquals(new Date((long)nb),attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals((long)nb,attr.getInteger());
+		assertEquals(nb,attr.getReal());
+		assertEquals((long)nb,attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2f(nb,0),attr.getPoint());
+		assertEquals(new Point3f(nb,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplIcon() throws Exception {
+		Image ic = VectorToolkit.image(1,1,false);
+		Attribute attr = new AttributeImpl(randomString(),ic);
+		
+		assertEquals(AttributeType.IMAGE, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(ic,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertEquals(ic,attr.getImage());
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(ic.toString(), attr.getString());
+		assertEquals(ic,attr.getJavaObject());
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplInt() throws Exception {
+		int nb = new Random().nextInt();
+		String txt = Long.toString(nb);
+		Attribute attr = new AttributeImpl(randomString(),nb);
+		
+		assertEquals(AttributeType.INTEGER, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(nb,((Number)attr.getValue()).intValue());
+		assertEquals(nb!=0, attr.getBoolean());
+		assertEquals(VectorToolkit.color(nb), attr.getColor());
+		assertEquals(new Date(nb),attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(nb,attr.getInteger());
+		assertEquals(nb,(int)attr.getReal());
+		assertEquals(nb,attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2f(nb,0),attr.getPoint());
+		assertEquals(new Point3f(nb,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplLong() throws Exception {
+		long nb = new Random().nextLong();
+		String txt = Long.toString(nb);
+		Attribute attr = new AttributeImpl(randomString(),nb);
+		
+		assertEquals(AttributeType.INTEGER, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(nb,((Number)attr.getValue()).longValue());
+		assertEquals(nb!=0, attr.getBoolean());
+		assertEquals(VectorToolkit.color((int)nb), attr.getColor());
+		assertEquals(new Date(nb),attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(nb,attr.getInteger());
+		assertEquals((double)nb,attr.getReal());
+		assertEquals(nb,attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2f(nb,0),attr.getPoint());
+		assertEquals(new Point3f(nb,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplPoint2d() throws Exception {
+		Point2D pt = new Point2f(Math.random(),Math.random());
+		Point3D pt3d = new Point3f(pt.getX(),pt.getY(),0.);
+		String str = pt.getX()+";"+pt.getY(); //$NON-NLS-1$
+		Attribute attr = new AttributeImpl(randomString(),pt);
+		
+		assertEquals(AttributeType.POINT, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(pt,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color(pt.getX(),pt.getY(),0f),attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(pt, attr.getJavaObject());
+		assertEquals(pt,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+	
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplDoubleDouble() throws Exception {
+		double x = Math.random();
+		double y = Math.random();
+		Point2D pt = new Point2f(x,y);
+		Point3D pt3d = new Point3f(x,y,0.);
+		String str = ((float)x)+";"+((float)y); //$NON-NLS-1$
+		Attribute attr = new AttributeImpl(randomString(),x,y);
+		
+		assertEquals(AttributeType.POINT, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(pt,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color(pt.getX(),pt.getY(),0f),attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(pt, attr.getJavaObject());
+		assertEquals(pt,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+	
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplPoint3d() throws Exception {
+		double x = Math.random();
+		double y = Math.random();
+		double z = Math.random();
+		Point3D pt = new Point3f(x,y,z);
+		Point2D pt2d = new Point2f(x,y);
+		String str = ((float)x)+";"+((float)y)+";"+((float)z); //$NON-NLS-1$ //$NON-NLS-2$
+		Attribute attr = new AttributeImpl(randomString(),pt);
+		
+		assertEquals(AttributeType.POINT3D, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(pt,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color(pt.getX(),pt.getY(),pt.getZ()),attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(pt, attr.getJavaObject());
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplDoubleDoubleDouble() throws Exception {
+		double x = Math.random();
+		double y = Math.random();
+		double z = Math.random();
+		Point3D pt = new Point3f(x,y,z);
+		Point2D pt2d = new Point2f(x,y);
+		String str = ((float)x)+";"+((float)y)+";"+((float)z); //$NON-NLS-1$ //$NON-NLS-2$
+		Attribute attr = new AttributeImpl(randomString(),x,y,z);
+		
+		assertEquals(AttributeType.POINT3D, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(pt,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color(pt.getX(),pt.getY(),pt.getZ()),attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(pt, attr.getJavaObject());
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_random() throws Exception {
+		double x = Math.random();
+		Point2D pt2d = new Point2f(x,0);
+		Point3D pt3d = new Point3f(x,0,0);
+		String str = Double.toHexString(x);
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertEquals(x,attr.getReal());
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_boolean() throws Exception {
+		String str = Boolean.toString(true);
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertTrue(attr.getBoolean());
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_Color() throws Exception {
+		Color c = VectorToolkit.RED;
+		Point2D pt2d = new Point2f(c.getRed(),c.getGreen());
+		Point2D pt2d2 = new Point2f(c.getBlue(),0);
+		Point3D pt3d = new Point3f(c.getRed(),c.getGreen(),c.getBlue());
+		String str = c.getRed()+";"+c.getGreen()+";"+c.getBlue();  //$NON-NLS-1$//$NON-NLS-2$
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(c,attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d,pt2d2},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_Date() throws Exception {
+		Date currentDate = new Date();
+		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
+		String str = format.format(currentDate); 
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertEpsilonEquals(currentDate,attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_JDate() throws Exception {
+		Date currentDate = new Date();
+		String str = DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL).format(currentDate); 
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertEpsilonEquals(currentDate,attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_Integer() throws Exception {
+		int nb = new Random().nextInt(20000)+256;
+		Point2D pt2d = new Point2f(nb,0);
+		Point3D pt3d = new Point3f(nb,0,0);
+		String str = Integer.toString(nb);
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(nb,attr.getInteger());
+		assertEquals((double)nb,attr.getReal());
+		assertEquals(nb,attr.getTimestamp());
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_Long() throws Exception {
+		long nb = new Random().nextInt(20000)+256;
+		Point2D pt2d = new Point2f(nb,0);
+		Point3D pt3d = new Point3f(nb,0,0);
+		String str = Long.toString(nb);
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(nb,attr.getInteger());
+		assertEquals((double)nb,attr.getReal());
+		assertEquals(nb,attr.getTimestamp());
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_Double() throws Exception {
+		double nb = Math.random()+256;
+		Point2D pt2d = new Point2f(nb,0);
+		Point3D pt3d = new Point3f(nb,0,0);
+		String str = Double.toString(nb);
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertEquals(nb,attr.getReal());
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_Point2D() throws Exception {
+		double x = Math.random()+256;
+		double y = Math.random()+256;
+		Point2D pt2d = new Point2f(x,y);
+		Point3D pt3d = new Point3f(x,y,0);
+		String str = x+";"+y; //$NON-NLS-1$
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplString_Point3D() throws Exception {
+		double x = Math.random()+256;
+		double y = Math.random()+256;
+		double z = Math.random()+256;
+		Point2D pt2d = new Point2f(x,y);
+		Point2D pt2d2 = new Point2f(z,0);
+		Point3D pt3d = new Point3f(x,y,z);
+		String str = x+";"+y+";"+z; //$NON-NLS-1$ //$NON-NLS-2$
+		Attribute attr = new AttributeImpl(randomString(),str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d,pt2d2},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplPoint2DArray() throws Exception {
+		double x1 = Math.random();
+		double y1 = Math.random();
+		double x2 = Math.random();
+		double y2 = Math.random();
+
+		Point2D pt1 = new Point2f(x1,y1);
+		Point2D pt2 = new Point2f(x2,y2);
+		
+		Point2D[] list = new Point2D[]{ pt1, pt2 };
+		Point3D[] list2 = new Point3D[]{ new Point3f(x1,y1,0), new Point3f(x2,y2,0) };
+
+		String str = ((float)x1)+";"+((float)y1)+";"+((float)x2)+";"+((float)y2); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+		Attribute attr = new AttributeImpl(randomString(),list);
+		
+		assertEquals(AttributeType.POLYLINE, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(list,(Point2D[])attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(list, attr.getJavaObject());
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertEquals(list,attr.getPolyline());
+		assertEquals(list2,attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeImplPoint3DArray() throws Exception {
+		double x1 = Math.random();
+		double y1 = Math.random();
+		double z1 = Math.random();
+		double x2 = Math.random();
+		double y2 = Math.random();
+		double z2 = Math.random();
+
+		Point3D pt1 = new Point3f(x1,y1,z1);
+		Point3D pt2 = new Point3f(x2,y2,z2);
+		
+		Point3D[] list = new Point3D[]{ pt1, pt2 };
+		Point2D[] list2 = new Point2D[]{ new Point2f(x1,y1), new Point2f(x2,y2) };
+
+		String str = ((float)x1)+";"+((float)y1)+";"+((float)z1)+";"+((float)x2)+";"+((float)y2)+";"+((float)z2); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+
+		Attribute attr = new AttributeImpl(randomString(),list);
+		
+		assertEquals(AttributeType.POLYLINE3D, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(list,(Point3D[])attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(list, attr.getJavaObject());
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertEquals(list2,attr.getPolyline());
+		assertEquals(list,attr.getPolyline3D());
+	}
+
+	/**
+	 */
+	public static void testEquals() {
+		AttributeImpl attr = new AttributeImpl("A1"); //$NON-NLS-1$
+		
+		attr.setBoolean(true);
+		assertTrue(attr.equals(new AttributeImpl("A1", true))); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeImpl("A1", false))); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeImpl("A2", true))); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeImpl("A2", false))); //$NON-NLS-1$
+		assertTrue(attr.equals(new AttributeValueImpl(true)));
+		assertFalse(attr.equals(new AttributeValueImpl(false)));
+		assertTrue(attr.equals(true));
+		assertFalse(attr.equals(false));
+		assertTrue(attr.equals(new AttributeValueImpl("true"))); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeValueImpl("false"))); //$NON-NLS-1$
+		assertTrue(attr.equals("true")); //$NON-NLS-1$
+		assertFalse(attr.equals("false")); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeValueImpl(1.)));
+		assertFalse(attr.equals(new AttributeValueImpl("1."))); //$NON-NLS-1$
+		assertFalse(attr.equals(1.));
+		assertFalse(attr.equals("toto")); //$NON-NLS-1$
+
+		attr.setBoolean(false);
+		assertFalse(attr.equals(new AttributeImpl("A1", true))); //$NON-NLS-1$
+		assertTrue(attr.equals(new AttributeImpl("A1", false))); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeImpl("A2", true))); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeImpl("A2", false))); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeValueImpl(true)));
+		assertTrue(attr.equals(new AttributeValueImpl(false)));
+		assertFalse(attr.equals(true));
+		assertTrue(attr.equals(false));
+		assertFalse(attr.equals(new AttributeValueImpl("true"))); //$NON-NLS-1$
+		assertTrue(attr.equals(new AttributeValueImpl("false"))); //$NON-NLS-1$
+		assertFalse(attr.equals("true")); //$NON-NLS-1$
+		assertTrue(attr.equals("false")); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeValueImpl(1.)));
+		assertFalse(attr.equals(new AttributeValueImpl("1."))); //$NON-NLS-1$
+		assertFalse(attr.equals(1.));
+		assertFalse(attr.equals("toto")); //$NON-NLS-1$
+	}
+	
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeTypeTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeTypeTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeTypeTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,1194 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.UUID;
+
+import org.arakhne.afc.attrs.AbstractAttrTestCase;
+import org.arakhne.afc.attrs.attr.AttributeConstants;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.NullAttribute;
+import org.arakhne.afc.attrs.attr.Timestamp;
+import org.arakhne.afc.math.continous.object2d.Point2f;
+import org.arakhne.afc.math.continous.object3d.Point3f;
+import org.arakhne.afc.math.discrete.object2d.Point2i;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Point3D;
+import org.arakhne.afc.math.generic.Tuple2D;
+import org.arakhne.afc.math.generic.Tuple3D;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+import org.arakhne.afc.ui.vector.VectorToolkit;
+
+/**
+ * Test of AttributeType.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeTypeTest extends AbstractAttrTestCase {
+
+	/** 
+	 * @param type
+	 * @param value
+	 */
+	protected static void assertCastException(AttributeType type, Object value) {
+		assertException(ClassCastException.class, type, "cast", new Class<?>[] {Object.class}, new Object[] {value}); //$NON-NLS-1$
+	}
+
+	/**
+	 * @param type
+	 * @param value
+	 */
+	protected static void assertNullException(AttributeType type, Object value) {
+		assertException(NullPointerException.class, type, "cast", new Class<?>[] {Object.class}, new Object[] {value}); //$NON-NLS-1$
+	}
+
+	/**
+	 */
+	public static void testGetName() {
+		for(AttributeType type : AttributeType.values()) {
+			String name = type.getName();
+			assertNotNull(name);
+			assertNotSame("", name); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 */
+	public static void testIsNumberType() {
+		for(AttributeType t : AttributeType.values()) {
+			assertEquals(t==AttributeType.INTEGER || t==AttributeType.REAL || t==AttributeType.TIMESTAMP,
+					t.isNumberType());
+			if (t.isNumberType()) assertTrue(t.isBaseType());
+		}
+	}
+
+	/**
+	 */
+	public static void testFromInteger() {
+		AttributeType[] types = AttributeType.values();
+		assertNotNull(types);
+		assertFalse(0==types.length);
+		for(int i=-1; i<types.length+10; ++i) {
+			AttributeType type = AttributeType.fromInteger(i);
+			assertNotNull(type);
+			if ((i<0)||(i>=types.length)) {
+				assertEquals(AttributeType.OBJECT, type);
+			}
+			else {
+				assertEquals(i,type.ordinal());
+				assertEquals(types[i],type);
+			}
+		}
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testFromValue() throws Exception {
+		assertEquals(AttributeType.OBJECT, AttributeType.fromValue(null));
+		assertEquals(AttributeType.BOOLEAN, AttributeType.fromValue(true));
+		assertEquals(AttributeType.STRING, AttributeType.fromValue('c'));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromValue((byte)1));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromValue((short)1));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromValue(1));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromValue(1l));
+		assertEquals(AttributeType.REAL, AttributeType.fromValue(1f));
+		assertEquals(AttributeType.REAL, AttributeType.fromValue(1.));
+		assertEquals(AttributeType.STRING, AttributeType.fromValue("Hello")); //$NON-NLS-1$
+		assertEquals(AttributeType.STRING, AttributeType.fromValue(new StringBuffer()));
+		assertEquals(AttributeType.STRING, AttributeType.fromValue(new StringBuilder()));
+		assertEquals(AttributeType.DATE, AttributeType.fromValue(Calendar.getInstance()));
+		assertEquals(AttributeType.DATE, AttributeType.fromValue(new Date()));
+		assertEquals(AttributeType.COLOR, AttributeType.fromValue(VectorToolkit.RED));
+		assertEquals(AttributeType.UUID, AttributeType.fromValue(UUID.randomUUID()));
+		assertEquals(AttributeType.POINT, AttributeType.fromValue(new Point2f(0,0)));
+		assertEquals(AttributeType.POINT, AttributeType.fromValue(new Point2i(0,0)));
+		assertEquals(AttributeType.POINT3D, AttributeType.fromValue(new Point3f(0,0,0)));
+		assertEquals(AttributeType.POLYLINE, AttributeType.fromValue(new Point2D[0]));
+		assertEquals(AttributeType.POLYLINE3D, AttributeType.fromValue(new Point3D[0]));
+		assertEquals(AttributeType.IMAGE, AttributeType.fromValue(VectorToolkit.image(1,1,false)));
+		assertEquals(AttributeType.UUID, AttributeType.fromValue(UUID.randomUUID()));
+		assertEquals(AttributeType.URL, AttributeType.fromValue(new URL("http://set.utbm.fr";))); //$NON-NLS-1$
+		assertEquals(AttributeType.URI, AttributeType.fromValue(new URI("http://set.utbm.fr";))); //$NON-NLS-1$
+		assertEquals(AttributeType.INET_ADDRESS, AttributeType.fromValue(InetAddress.getLocalHost()));
+		AttributeType randomType = randomEnum(AttributeType.class);
+		assertEquals(AttributeType.ENUMERATION, AttributeType.fromValue(randomType));
+		assertEquals(AttributeType.OBJECT, AttributeType.fromValue(new int[0]));
+		assertEquals(AttributeType.OBJECT, AttributeType.fromValue(Locale.getDefault()));
+		assertEquals(AttributeType.TYPE, AttributeType.fromValue(AttributeTypeTest.class));
+		assertEquals(AttributeType.TYPE, AttributeType.fromValue(double.class));
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testFromClass() throws Exception {
+		assertEquals(AttributeType.OBJECT, AttributeType.fromClass(null));
+		assertEquals(AttributeType.BOOLEAN, AttributeType.fromClass(boolean.class));
+		assertEquals(AttributeType.BOOLEAN, AttributeType.fromClass(Boolean.class));
+		assertEquals(AttributeType.STRING, AttributeType.fromClass(char.class));
+		assertEquals(AttributeType.STRING, AttributeType.fromClass(Character.class));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromClass(byte.class));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromClass(Byte.class));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromClass(short.class));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromClass(Short.class));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromClass(int.class));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromClass(Integer.class));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromClass(long.class));
+		assertEquals(AttributeType.INTEGER, AttributeType.fromClass(Long.class));
+		assertEquals(AttributeType.REAL, AttributeType.fromClass(float.class));
+		assertEquals(AttributeType.REAL, AttributeType.fromClass(Float.class));
+		assertEquals(AttributeType.REAL, AttributeType.fromClass(double.class));
+		assertEquals(AttributeType.REAL, AttributeType.fromClass(Double.class));
+		assertEquals(AttributeType.STRING, AttributeType.fromClass(String.class));
+		assertEquals(AttributeType.STRING, AttributeType.fromClass(StringBuffer.class));
+		assertEquals(AttributeType.STRING, AttributeType.fromClass(StringBuilder.class));
+		assertEquals(AttributeType.DATE, AttributeType.fromClass(Calendar.class));
+		assertEquals(AttributeType.DATE, AttributeType.fromClass(Date.class));
+		assertEquals(AttributeType.COLOR, AttributeType.fromClass(Color.class));
+		assertEquals(AttributeType.UUID, AttributeType.fromClass(UUID.class));
+		assertEquals(AttributeType.POINT, AttributeType.fromClass(Point2D.class));
+		assertEquals(AttributeType.POINT, AttributeType.fromClass(Point2D.class));
+		assertEquals(AttributeType.POINT3D, AttributeType.fromClass(Point3D.class));
+		assertEquals(AttributeType.OBJECT, AttributeType.fromClass(Tuple2D[].class));
+		assertEquals(AttributeType.POLYLINE, AttributeType.fromClass(Point2D[].class));
+		assertEquals(AttributeType.OBJECT, AttributeType.fromClass(Tuple3D[].class));
+		assertEquals(AttributeType.POLYLINE3D, AttributeType.fromClass(Point3D[].class));
+		assertEquals(AttributeType.IMAGE, AttributeType.fromClass(Image.class));
+		assertEquals(AttributeType.UUID, AttributeType.fromClass(UUID.class));
+		assertEquals(AttributeType.URL, AttributeType.fromClass(URL.class));
+		assertEquals(AttributeType.URI, AttributeType.fromClass(URI.class));
+		assertEquals(AttributeType.INET_ADDRESS, AttributeType.fromClass(InetAddress.class));
+		assertEquals(AttributeType.ENUMERATION, AttributeType.fromClass(AttributeType.class));
+		assertEquals(AttributeType.OBJECT, AttributeType.fromClass(int[].class));
+		assertEquals(AttributeType.OBJECT, AttributeType.fromClass(Locale.class));
+		assertEquals(AttributeType.TYPE, AttributeType.fromClass(Class.class));
+	}
+
+	/**
+	 */
+	public static void testIsBaseType() {
+		assertTrue(AttributeType.BOOLEAN.isBaseType());
+		assertTrue(AttributeType.INTEGER.isBaseType());
+		assertTrue(AttributeType.REAL.isBaseType());
+		assertTrue(AttributeType.STRING.isBaseType());
+		assertTrue(AttributeType.TIMESTAMP.isBaseType());
+		
+		assertFalse(AttributeType.COLOR.isBaseType());
+		assertFalse(AttributeType.DATE.isBaseType());
+		assertFalse(AttributeType.IMAGE.isBaseType());
+		assertFalse(AttributeType.OBJECT.isBaseType());
+		assertFalse(AttributeType.POINT.isBaseType());
+		assertFalse(AttributeType.POINT3D.isBaseType());
+		assertFalse(AttributeType.POLYLINE.isBaseType());
+		assertFalse(AttributeType.POLYLINE3D.isBaseType());
+		assertFalse(AttributeType.URL.isBaseType());
+		assertFalse(AttributeType.URI.isBaseType());
+		assertFalse(AttributeType.UUID.isBaseType());
+		assertFalse(AttributeType.INET_ADDRESS.isBaseType());
+		assertFalse(AttributeType.ENUMERATION.isBaseType());
+		assertFalse(AttributeType.TYPE.isBaseType());
+	}
+	
+	/**
+	 */
+	public static void testIsNullAllowed() {
+		assertFalse(AttributeType.BOOLEAN.isNullAllowed());
+		assertFalse(AttributeType.INTEGER.isNullAllowed());
+		assertFalse(AttributeType.REAL.isNullAllowed());
+		assertFalse(AttributeType.STRING.isNullAllowed());
+		assertFalse(AttributeType.TIMESTAMP.isNullAllowed());
+		
+		assertFalse(AttributeType.COLOR.isNullAllowed());
+		assertFalse(AttributeType.DATE.isNullAllowed());
+		assertTrue(AttributeType.IMAGE.isNullAllowed());
+		assertTrue(AttributeType.OBJECT.isNullAllowed());
+		assertFalse(AttributeType.POINT.isNullAllowed());
+		assertFalse(AttributeType.POINT3D.isNullAllowed());
+		assertFalse(AttributeType.POLYLINE.isNullAllowed());
+		assertFalse(AttributeType.POLYLINE3D.isNullAllowed());
+		assertTrue(AttributeType.URL.isNullAllowed());
+		assertTrue(AttributeType.URI.isNullAllowed());
+		assertFalse(AttributeType.UUID.isNullAllowed());
+		assertTrue(AttributeType.INET_ADDRESS.isNullAllowed());
+		assertTrue(AttributeType.ENUMERATION.isNullAllowed());
+		assertFalse(AttributeType.TYPE.isNullAllowed());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testGetDefaultValue() throws Exception {
+		assertEquals(Boolean.FALSE, AttributeType.BOOLEAN.getDefaultValue());
+		assertEquals(new Long(0), AttributeType.INTEGER.getDefaultValue());
+		assertEquals(new Double(0.), AttributeType.REAL.getDefaultValue());
+		assertEquals(new String(), AttributeType.STRING.getDefaultValue());
+		assertNotNull(AttributeType.TIMESTAMP.getDefaultValue());
+		
+		assertEquals(VectorToolkit.color(0,0,0), AttributeType.COLOR.getDefaultValue());
+		assertNotNull(AttributeType.DATE.getDefaultValue());
+		assertNull(AttributeType.IMAGE.getDefaultValue());
+		assertNull(AttributeType.OBJECT.getDefaultValue());
+		assertEquals(new Point2f(), AttributeType.POINT.getDefaultValue());
+		assertEquals(new Point3f(), AttributeType.POINT3D.getDefaultValue());
+		assertTrue(Arrays.equals(new Point2D[0], (Point2D[])AttributeType.POLYLINE.getDefaultValue()));
+		assertTrue(Arrays.equals(new Point3D[0], (Point3D[])AttributeType.POLYLINE3D.getDefaultValue()));
+		assertNull(AttributeType.URL.getDefaultValue());
+		assertNull(AttributeType.URI.getDefaultValue());
+		assertEquals(java.util.UUID.fromString("00000000-0000-0000-0000-000000000000"), AttributeType.UUID.getDefaultValue()); //$NON-NLS-1$
+		assertEquals(InetAddress.getLocalHost(), AttributeType.INET_ADDRESS.getDefaultValue());
+		assertNull(AttributeType.ENUMERATION.getDefaultValue());
+		assertEquals(Object.class, AttributeType.TYPE.getDefaultValue());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testCast() throws Exception {
+		AttributeType type;
+		char vChar = 'c';
+		byte vByte = 1;
+		short vShort = 1;
+		int vInt = 1;
+		long vLong = 1;
+		float vFloat = 1f;
+		double vDouble = 1.;
+		String vStr = "Hello"; //$NON-NLS-1$
+		StringBuilder vStrB = new StringBuilder("World"); //$NON-NLS-1$
+		Calendar cal = Calendar.getInstance();
+		Date dt = new Date();
+		Point2f pt2d1 = new Point2f(0,0);
+		Image img = VectorToolkit.image(1,1,false);
+		Color col = VectorToolkit.RED;
+		UUID uuid = UUID.nameUUIDFromBytes("abcd".getBytes()); //$NON-NLS-1$
+		Point3D pt3d = new Point3f(0,0,0);
+		Point2D[] tabpt2d1 = new Point2D[0];
+		Point3D[] tabpt3d = new Point3D[0];
+		int[] tabint = new int[0];
+		Object obj = Locale.getDefault();
+		URL url = new URL("http://set.utbm.fr";); //$NON-NLS-1$
+		URI uri = new URI("http://set.utbm.fr";); //$NON-NLS-1$
+		InetAddress ipAddress = InetAddress.getLocalHost();
+		String vIpStr = ipAddress.toString();
+		AttributeType enumeration = randomEnum(AttributeType.class);
+		String vEnumStr = AttributeType.class.getCanonicalName()+"."+AttributeType.values()[1].name(); //$NON-NLS-1$
+		
+		// BOOLEAN
+		type = AttributeType.BOOLEAN;
+		assertNullException(type,null);
+		assertEquals(Boolean.TRUE, type.cast(true));
+		assertEquals(Boolean.FALSE, type.cast(false));
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// COLOR
+		type = AttributeType.COLOR;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertEquals(VectorToolkit.color(vByte), type.cast(vByte));
+		assertEquals(VectorToolkit.color(vShort), type.cast(vShort));
+		assertEquals(VectorToolkit.color(vInt), type.cast(vInt));
+		assertEquals(VectorToolkit.color((int)vLong), type.cast(vLong));
+		assertEquals(VectorToolkit.color((int)vFloat), type.cast(vFloat));
+		assertEquals(VectorToolkit.color((int)vDouble), type.cast(vDouble));
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertSame(col,type.cast(col));
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// UUID
+		type = AttributeType.UUID;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertSame(uuid,type.cast(uuid));
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// DATE
+		type = AttributeType.DATE;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertEquals(new Date(vByte),type.cast(vByte));
+		assertEquals(new Date(vShort),type.cast(vShort));
+		assertEquals(new Date(vInt),type.cast(vInt));
+		assertEquals(new Date(vLong),type.cast(vLong));
+		assertEquals(new Date((long)vFloat),type.cast(vFloat));
+		assertEquals(new Date((long)vDouble),type.cast(vDouble));
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertEquals(cal.getTime(),type.cast(cal));
+		assertSame(dt,type.cast(dt));
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// ICON
+		type = AttributeType.IMAGE;
+		assertEquals(new NullAttribute(type),type.cast(null));
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertNotNull(type.cast(img));
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// INTEGER
+		type = AttributeType.INTEGER;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertEquals((long)vByte,type.cast(vByte));
+		assertEquals((long)vShort,type.cast(vShort));
+		assertEquals((long)vInt,type.cast(vInt));
+		assertEquals(vLong,type.cast(vLong));
+		assertEquals((long)vFloat,type.cast(vFloat));
+		assertEquals((long)vDouble,type.cast(vDouble));
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertEquals((long)enumeration.ordinal(), type.cast(enumeration));
+
+		// OBJECT
+		type = AttributeType.OBJECT;
+		assertEquals(new NullAttribute(type),type.cast(null));
+		assertEquals(true,type.cast(true));
+		assertEquals(false,type.cast(false));
+		assertEquals(vChar,type.cast(vChar));
+		assertEquals(vByte,type.cast(vByte));
+		assertEquals(vShort,type.cast(vShort));
+		assertEquals(vInt,type.cast(vInt));
+		assertEquals(vLong,type.cast(vLong));
+		assertEquals(vFloat, type.cast(vFloat));
+		assertEquals(vDouble,type.cast(vDouble));
+		assertEquals(vStr,type.cast(vStr));
+		assertEquals(vStrB,type.cast(vStrB));
+		assertSame(cal,type.cast(cal));
+		assertSame(dt,type.cast(dt));
+		assertSame(col,type.cast(col));
+		assertSame(uuid,type.cast(uuid));
+		assertSame(pt2d1,type.cast(pt2d1));
+		assertSame(pt3d,type.cast(pt3d));
+		assertSame(tabpt2d1,type.cast(tabpt2d1));
+		assertSame(tabpt3d,type.cast(tabpt3d));
+		assertSame(img,type.cast(img));
+		assertSame(tabint,type.cast(tabint));
+		assertSame(obj,type.cast(obj));
+		assertSame(url,type.cast(url));
+		assertSame(uri,type.cast(uri));
+		assertSame(ipAddress, type.cast(ipAddress));
+		assertSame(enumeration,type.cast(enumeration));
+
+		// POINT
+		type = AttributeType.POINT;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertSame(pt2d1,type.cast(pt2d1));
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// POINT3D
+		type = AttributeType.POINT3D;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertSame(pt3d,type.cast(pt3d));
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// POLYLINE
+		type = AttributeType.POLYLINE;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertSame(tabpt2d1,type.cast(tabpt2d1));
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// POLYINE3D
+		type = AttributeType.POLYLINE3D;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertSame(tabpt3d,type.cast(tabpt3d));
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// REAL
+		type = AttributeType.REAL;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertEquals((double)vByte,type.cast(vByte));
+		assertEquals((double)vShort,type.cast(vShort));
+		assertEquals((double)vInt,type.cast(vInt));
+		assertEquals((double)vLong,type.cast(vLong));
+		assertEquals((double)vFloat,type.cast(vFloat));
+		assertEquals(vDouble,type.cast(vDouble));
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertEquals((double)enumeration.ordinal(), type.cast(enumeration));
+
+		// STRING
+		type = AttributeType.STRING;
+		assertEquals(type.getDefaultValue(),type.cast(null));
+		assertEquals(Boolean.toString(true),type.cast(true));
+		assertEquals(Boolean.toString(false),type.cast(false));
+		assertEquals(Character.toString(vChar),type.cast(vChar));
+		assertEquals(Byte.toString(vByte),type.cast(vByte));
+		assertEquals(Short.toString(vShort),type.cast(vShort));
+		assertEquals(Integer.toString(vInt),type.cast(vInt));
+		assertEquals(Long.toString(vLong),type.cast(vLong));
+		assertEquals(Float.toString(vFloat),type.cast(vFloat));
+		assertEquals(Double.toString(vDouble),type.cast(vDouble));
+		assertEquals(vStr,type.cast(vStr));
+		assertEquals(vStrB.toString(),type.cast(vStrB));
+		assertEquals(cal.toString(),type.cast(cal));
+		assertEquals(dt.toString(),type.cast(dt));
+		assertEquals(col.toString(),type.cast(col));
+		assertEquals(uuid.toString(),type.cast(uuid));
+		assertEquals(pt2d1.toString(),type.cast(pt2d1));
+		assertEquals(pt3d.toString(),type.cast(pt3d));
+		assertEquals(tabpt2d1.toString(),type.cast(tabpt2d1));
+		assertEquals(tabpt3d.toString(),type.cast(tabpt3d));
+		assertEquals(img.toString(),type.cast(img));
+		assertEquals(tabint.toString(),type.cast(tabint));
+		assertEquals(obj.toString(),type.cast(obj));
+		assertEquals(url.toString(), type.cast(url));
+		assertEquals(uri.toString(), type.cast(uri));
+		assertEquals(ipAddress.toString(), type.cast(ipAddress));
+		assertEquals(enumeration.getClass().getCanonicalName()+"."+enumeration.name(), type.cast(enumeration)); //$NON-NLS-1$
+
+		// TIMESTAMP
+		type = AttributeType.TIMESTAMP;
+		assertNullException(type,null);
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertEquals(new Timestamp(vByte),type.cast(vByte));
+		assertEquals(new Timestamp(vShort),type.cast(vShort));
+		assertEquals(new Timestamp(vInt),type.cast(vInt));
+		assertEquals(new Timestamp(vLong),type.cast(vLong));
+		assertEquals(new Timestamp((int)vFloat),type.cast(vFloat));
+		assertEquals(new Timestamp((int)vDouble),type.cast(vDouble));
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertEquals(cal.getTimeInMillis(),type.cast(cal));
+		assertEquals(dt.getTime(),type.cast(dt));
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertCastException(type,enumeration);
+
+		// URI
+		type = AttributeType.URI;
+		assertEquals(new NullAttribute(type),type.cast(null));
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertEquals(url.toURI(), type.cast(url));
+		assertSame(uri, type.cast(uri));
+		assertEquals(new URI(AttributeConstants.DEFAULT_SCHEME.name(), ipAddress.getHostAddress(), ""), type.cast(ipAddress)); //$NON-NLS-1$
+		assertCastException(type,enumeration);
+
+		// URL
+		type = AttributeType.URL;
+		assertEquals(new NullAttribute(type),type.cast(null));
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertSame(url, type.cast(url));
+		assertEquals(uri.toURL(), type.cast(uri));
+		assertEquals(new URL(AttributeConstants.DEFAULT_SCHEME.name(), ipAddress.getHostAddress(), ""), type.cast(ipAddress)); //$NON-NLS-1$
+		assertCastException(type,enumeration);
+
+		// INET_ADDRESS
+		type = AttributeType.INET_ADDRESS;
+		assertEquals(new NullAttribute(type),type.cast(null));
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertEquals(ipAddress,type.cast(vIpStr));
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertEquals(InetAddress.getByName("set.utbm.fr"), type.cast(url)); //$NON-NLS-1$
+		assertEquals(InetAddress.getByName("set.utbm.fr"), type.cast(uri)); //$NON-NLS-1$
+		assertSame(ipAddress, type.cast(ipAddress));
+		assertCastException(type,enumeration);
+
+		// ENUMERATION
+		type = AttributeType.ENUMERATION;
+		assertEquals(new NullAttribute(type),type.cast(null));
+		assertCastException(type,true);
+		assertCastException(type,false);
+		assertCastException(type,vChar);
+		assertCastException(type,vByte);
+		assertCastException(type,vShort);
+		assertCastException(type,vInt);
+		assertCastException(type,vLong);
+		assertCastException(type,vFloat);
+		assertCastException(type,vDouble);
+		assertCastException(type,vStr);
+		assertSame(AttributeType.values()[1],type.cast(vEnumStr));
+		assertCastException(type,vStrB);
+		assertCastException(type,cal);
+		assertCastException(type,dt);
+		assertCastException(type,col);
+		assertCastException(type,uuid);
+		assertCastException(type,pt2d1);
+		assertCastException(type,pt3d);
+		assertCastException(type,tabpt2d1);
+		assertCastException(type,tabpt3d);
+		assertCastException(type,img);
+		assertCastException(type,tabint);
+		assertCastException(type,obj);
+		assertCastException(type,url);
+		assertCastException(type,uri);
+		assertCastException(type,ipAddress);
+		assertSame(enumeration,type.cast(enumeration));
+	}
+
+	/**
+	 */
+	public static void testIsAssignableFrom() {
+		assertTrue(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.COLOR));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.BOOLEAN.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.BOOLEAN));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.OBJECT));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.POINT));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.COLOR.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.COLOR.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.DATE.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.DATE.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.DATE.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.DATE.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.DATE.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.DATE.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.DATE.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.COLOR));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.DATE));
+		assertTrue(AttributeType.IMAGE.isAssignableFrom(AttributeType.IMAGE));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.IMAGE.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.REAL));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.STRING));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.IMAGE.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.INTEGER.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertTrue(AttributeType.INTEGER.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.BOOLEAN));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.DATE));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.OBJECT));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.POINT));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.POINT3D));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.POLYLINE));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.URI));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.URL));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.UUID));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertTrue(AttributeType.OBJECT.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.BOOLEAN));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.OBJECT));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.POINT));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.POINT.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.POINT.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.BOOLEAN));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.OBJECT));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.POINT));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.POINT3D.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.POINT3D.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.COLOR));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.IMAGE));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.POLYLINE.isAssignableFrom(AttributeType.OBJECT));
+		assertTrue(AttributeType.POLYLINE.isAssignableFrom(AttributeType.POINT));
+		assertTrue(AttributeType.POLYLINE.isAssignableFrom(AttributeType.POINT3D));
+		assertTrue(AttributeType.POLYLINE.isAssignableFrom(AttributeType.POLYLINE));
+		assertTrue(AttributeType.POLYLINE.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.POLYLINE.isAssignableFrom(AttributeType.STRING));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.POLYLINE.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.COLOR));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.IMAGE));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.OBJECT));
+		assertTrue(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.POINT));
+		assertTrue(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.POINT3D));
+		assertTrue(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.POLYLINE));
+		assertTrue(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.STRING));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.POLYLINE3D.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.BOOLEAN));
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.REAL.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertTrue(AttributeType.REAL.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.BOOLEAN));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.DATE));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.OBJECT));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.POINT));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.POINT3D));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.POLYLINE));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.URI));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.URL));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.UUID));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertTrue(AttributeType.STRING.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertTrue(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.BOOLEAN));
+		assertTrue(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.UUID));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.TIMESTAMP.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.COLOR));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.IMAGE));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.URI.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.URI.isAssignableFrom(AttributeType.STRING));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertTrue(AttributeType.URI.isAssignableFrom(AttributeType.URI));
+		assertTrue(AttributeType.URI.isAssignableFrom(AttributeType.URL));
+		assertTrue(AttributeType.URI.isAssignableFrom(AttributeType.UUID));
+		assertTrue(AttributeType.URI.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.URI.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.COLOR));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.IMAGE));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.URL.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.URL.isAssignableFrom(AttributeType.STRING));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertTrue(AttributeType.URL.isAssignableFrom(AttributeType.URI));
+		assertTrue(AttributeType.URL.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.UUID));
+		assertTrue(AttributeType.URL.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.URL.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.BOOLEAN));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.COLOR));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.DATE));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.IMAGE));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.OBJECT));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.POINT));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.POINT3D));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.POLYLINE));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.STRING));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.URI));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.URL));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.UUID));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertTrue(AttributeType.UUID.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.COLOR));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.IMAGE));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.STRING));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertTrue(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.URI));
+		assertTrue(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.URL));
+		assertTrue(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertFalse(AttributeType.INET_ADDRESS.isAssignableFrom(AttributeType.ENUMERATION));
+
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.BOOLEAN));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.COLOR));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.DATE));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.IMAGE));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.INTEGER));
+		assertTrue(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.OBJECT));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.POINT));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.POINT3D));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.POLYLINE));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.POLYLINE3D));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.REAL));
+		assertTrue(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.STRING));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.TIMESTAMP));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.URI));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.URL));
+		assertFalse(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.INET_ADDRESS));
+		assertTrue(AttributeType.ENUMERATION.isAssignableFrom(AttributeType.ENUMERATION));
+	}
+
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeValueComparatorTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeValueComparatorTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeValueComparatorTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,107 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import org.arakhne.afc.attrs.AbstractAttrTestCase;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeValueComparator;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+
+/**
+ * Test of AttributeValueComparator.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeValueComparatorTest extends AbstractAttrTestCase {
+
+	/**
+	 * @throws AttributeException
+	 */
+	public static void testCompare() throws AttributeException {
+		double base_d = Math.random();
+		long base_l = (long)base_d;
+		AttributeValueImpl attr1 = new AttributeValueImpl(base_d);		
+		AttributeValueImpl attr2 = new AttributeValueImpl(base_d+1);
+		AttributeValueImpl attr3 = new AttributeValueImpl(base_d-1);
+		
+		AttributeValueImpl attr4 = new AttributeValueImpl(base_l);		
+		AttributeValueImpl attr5 = new AttributeValueImpl(attr1.getInteger());
+		
+		AttributeValueImpl attr6 = new AttributeValueImpl("bonjour"); //$NON-NLS-1$
+		
+		AttributeValueComparator comp = new AttributeValueComparator();
+			
+		//----------- attr1 -> *
+		assertEquals(0, comp.compare(attr1,attr1));
+		assertStrictlyNegative(comp.compare(attr1,attr2));
+		assertStrictlyPositive(comp.compare(attr1,attr3));
+		assertPositive(comp.compare(attr1,attr4));
+		assertPositive(comp.compare(attr1,attr5));
+		assertStrictlyNegative(comp.compare(attr1,attr6));
+
+		//----------- attr2 -> *
+		assertStrictlyPositive(comp.compare(attr2,attr1));
+		assertEquals(0, comp.compare(attr2,attr2));
+		assertStrictlyPositive(comp.compare(attr2,attr3));
+		assertStrictlyPositive(comp.compare(attr2,attr4));
+		assertStrictlyPositive(comp.compare(attr2,attr5));
+		assertStrictlyNegative(comp.compare(attr2,attr6));
+
+		//----------- attr3 -> *
+		assertStrictlyNegative(comp.compare(attr3,attr1));
+		assertStrictlyNegative(comp.compare(attr3,attr2));
+		assertEquals(0, comp.compare(attr3,attr3));
+		assertStrictlyNegative(comp.compare(attr3,attr4));
+		assertStrictlyNegative(comp.compare(attr3,attr5));
+		assertStrictlyNegative(comp.compare(attr3,attr6));
+		
+
+		//----------- attr4 -> *
+		assertNegative(comp.compare(attr4,attr1));
+		assertStrictlyNegative(comp.compare(attr4,attr2));
+		assertStrictlyPositive(comp.compare(attr4,attr3));
+		assertEquals(0, comp.compare(attr4,attr4));
+		assertEquals(0,comp.compare(attr4,attr5));
+		assertStrictlyNegative(comp.compare(attr4,attr6));
+
+		//----------- attr5 -> *
+		assertNegative(comp.compare(attr5,attr1));
+		assertStrictlyNegative(comp.compare(attr5,attr2));
+		assertStrictlyPositive(comp.compare(attr5,attr3));
+		assertEquals(0,comp.compare(attr5,attr4));
+		assertEquals(0, comp.compare(attr5,attr5));
+		assertStrictlyNegative(comp.compare(attr5,attr6));
+
+		//----------- attr6 -> *
+		assertStrictlyPositive(comp.compare(attr6,attr1));
+		assertStrictlyPositive(comp.compare(attr6,attr2));
+		assertStrictlyPositive(comp.compare(attr6,attr3));
+		assertStrictlyPositive(comp.compare(attr6,attr4));
+		assertStrictlyPositive(comp.compare(attr6,attr5));
+		assertEquals(0, comp.compare(attr6,attr6));
+	}
+
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeValueTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeValueTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/attr/AttributeValueTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,3494 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.attr;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Random;
+
+import org.arakhne.afc.attrs.AbstractAttrTestCase;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeNotInitializedException;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.attrs.attr.InvalidAttributeTypeException;
+import org.arakhne.afc.attrs.attr.Timestamp;
+import org.arakhne.afc.math.continous.object2d.Point2f;
+import org.arakhne.afc.math.continous.object3d.Point3f;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Point3D;
+import org.arakhne.afc.ui.vector.Color;
+import org.arakhne.afc.ui.vector.Image;
+import org.arakhne.afc.ui.vector.VectorToolkit;
+
+/**
+ * Test of AttributeValue.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AttributeValueTest extends AbstractAttrTestCase {
+
+	/**
+	 * @param attr
+	 * @param type
+	 */
+	protected static void assertAllGetFailed(AttributeValue attr, AttributeType type) {
+		try {
+			attr.getValue();
+			fail("getValue: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getBoolean();
+			fail("getBoolean: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getColor();
+			fail("getColor: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getDate();
+			fail("getDate: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getImage();
+			fail("getImage: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getInteger();
+			fail("getInteger: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getJavaObject();
+			if (type.isBaseType())
+				fail("getJavaObject: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getPoint();
+			fail("getPoint: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getPoint3D();
+			fail("getPoint3D: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getPolyline();
+			fail("getPolyline: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getPolyline3D();
+			fail("getPolyline3D: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getReal();
+			fail("getReal: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getString();
+			fail("getString: the exception AttributeNotInitializedException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeNotInitializedException _) {
+			//
+		}
+		catch(InvalidAttributeTypeException _) {
+			if (!attr.isObjectValue())
+				fail("unexpected exception InvalidAttributeTypeException for "+type); //$NON-NLS-1$
+		}
+
+		try {
+			attr.getTimestamp();
+			fail("getTimestamp: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getUUID();
+			fail("getUUID: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getURI();
+			fail("getURI: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+
+		try {
+			attr.getURL();
+			fail("getURL: the exception InvalidAttributeTypeException was not thrown for "+type); //$NON-NLS-1$
+		}
+		catch(AttributeException _) {
+			// expected case
+		}
+	}
+
+	/**
+	 * @param attr
+	 * @param methodName
+	 * @throws Exception
+	 */
+	protected static void assertAttributeException(AttributeValue attr, String methodName) throws Exception {
+		try {
+			Class<? extends AttributeValue> clazz = attr.getClass();
+			Method method = clazz.getMethod(methodName);
+			method.invoke(attr);
+			fail("the exception AttributeException was not thrown"); //$NON-NLS-1$
+		}
+		catch(InvocationTargetException e) {
+			Throwable ex = e.getTargetException();
+			if (ex instanceof AssertionError) {
+				throw (AssertionError)ex;
+			}
+			if (ex instanceof AttributeException) {
+				//
+			}
+			else {
+				fail("the exception AttributeException was not thrown"); //$NON-NLS-1$
+			}
+		}
+	}
+
+	/**
+	 */
+	public static void testAttributeValueImpl() {
+		AttributeValue attr = new AttributeValueImpl();
+		
+		assertFalse(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(AttributeType.OBJECT, attr.getType());
+		
+		try {
+			attr.getValue();
+			fail("the exception AttributeNotInitializedException was not thrown"); //$NON-NLS-1$
+		}
+		catch(AttributeNotInitializedException _) {
+			// expected case
+		}
+		catch(InvalidAttributeTypeException _) {
+			fail("unexpected exception InvalidAttributeTypeException"); //$NON-NLS-1$
+		}
+
+		try {
+			attr.getBoolean();
+			fail("the exception AttributeNotInitializedException was not thrown"); //$NON-NLS-1$
+		}
+		catch(AttributeNotInitializedException _) {
+			// expected case
+		}
+		catch(InvalidAttributeTypeException _) {
+			fail("unexpected exception InvalidAttributeTypeException"); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplAttributeType() throws Exception {
+		AttributeType[] values = AttributeType.values();
+		//AttributeType[] values = new AttributeType[] {AttributeType.OBJECT};
+		for (AttributeType type : values) {
+			AttributeValue attr = new AttributeValueImpl(type);
+			
+			assertEquals(type, attr.getType());
+
+			assertFalse(attr.isAssigned());
+			assertEquals(type.isBaseType(),attr.isBaseType());
+			assertEquals("on type "+type, //$NON-NLS-1$
+					!type.isBaseType(),
+					attr.isObjectValue());
+			
+			if (type.isNullAllowed()) {
+				assertAttributeException(attr, "getBoolean"); //$NON-NLS-1$
+				assertAttributeException(attr, "getColor"); //$NON-NLS-1$
+				assertAttributeException(attr, "getDate"); //$NON-NLS-1$
+				assertAttributeException(attr, "getImage"); //$NON-NLS-1$
+				assertAttributeException(attr, "getInteger"); //$NON-NLS-1$
+				assertNull(attr.getJavaObject());
+				assertAttributeException(attr, "getPoint"); //$NON-NLS-1$
+				assertAttributeException(attr, "getPoint3D"); //$NON-NLS-1$
+				assertAttributeException(attr, "getPolyline"); //$NON-NLS-1$
+				assertAttributeException(attr, "getPolyline3D"); //$NON-NLS-1$
+				assertAttributeException(attr, "getReal"); //$NON-NLS-1$
+				assertAttributeException(attr, "getString"); //$NON-NLS-1$
+				assertAttributeException(attr, "getTimestamp"); //$NON-NLS-1$
+				assertAttributeException(attr, "getURI"); //$NON-NLS-1$
+				assertAttributeException(attr, "getURL"); //$NON-NLS-1$
+				assertAttributeException(attr, "getUUID"); //$NON-NLS-1$
+				assertAttributeException(attr, "getValue"); //$NON-NLS-1$
+			}
+			else {
+				assertAllGetFailed(attr, type);
+			}
+		}
+	}
+	
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplBoolean() throws Exception {
+		AttributeValue attr = new AttributeValueImpl(false);
+		
+		assertEquals(AttributeType.BOOLEAN, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertFalse((Boolean)attr.getValue());
+		assertFalse(attr.getBoolean());
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(0, attr.getInteger());
+		assertEquals(0., attr.getReal());
+		assertEquals(0, attr.getTimestamp());
+		assertEquals(Boolean.toString(false),attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplColor() throws Exception {
+		String txt = "255;0;0;255"; //$NON-NLS-1$
+		AttributeValue attr = new AttributeValueImpl(VectorToolkit.RED);
+		
+		assertEquals(AttributeType.COLOR, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(VectorToolkit.RED,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.RED,attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.RED.getRGB(), attr.getInteger());
+		assertEquals((double)VectorToolkit.RED.getRGB(), attr.getReal());
+		assertEquals(VectorToolkit.RED.getRGB(), attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertEquals(VectorToolkit.RED, attr.getJavaObject());
+		assertEquals(new Point2f(255,0),attr.getPoint());
+		assertEquals(new Point3f(255,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplDate() throws Exception {
+		Date currentDate = new Date();
+		SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
+		String txt = fmt.format(currentDate);
+		AttributeValue attr = new AttributeValueImpl(currentDate);
+		
+		assertEquals(AttributeType.DATE, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(currentDate,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color((int)currentDate.getTime()), attr.getColor());
+		assertEquals(currentDate,attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(currentDate.getTime(),attr.getInteger());
+		assertEquals((double)currentDate.getTime(),attr.getReal());
+		assertEquals(currentDate.getTime(),attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertEquals(currentDate, attr.getJavaObject());
+		assertEquals(new Point2f(currentDate.getTime(), 0), attr.getPoint());
+		assertEquals(new Point3f(currentDate.getTime(), 0, 0), attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplFloat() throws Exception {
+		float nb = (float)Math.random();
+		String txt = Double.toString(nb);
+		AttributeValue attr = new AttributeValueImpl(nb);
+		
+		assertEquals(AttributeType.REAL, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(nb,((Number)attr.getValue()).floatValue());
+		assertEquals(nb!=0f, attr.getBoolean());
+		assertEquals(VectorToolkit.color((int)nb), attr.getColor());
+		assertEquals(new Date((long)nb),attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals((long)nb,attr.getInteger());
+		assertEquals((double)nb,attr.getReal());
+		assertEquals((long)nb,attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2f(nb,0),attr.getPoint());
+		assertEquals(new Point3f(nb,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplDouble() throws Exception {
+		double nb = Math.random();
+		String txt = Double.toString(nb);
+		AttributeValue attr = new AttributeValueImpl(nb);
+		
+		assertEquals(AttributeType.REAL, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(nb,((Number)attr.getValue()).doubleValue());
+		assertEquals(nb!=0., attr.getBoolean());
+		assertEquals(VectorToolkit.color((int)nb), attr.getColor());
+		assertEquals(new Date((long)nb),attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals((long)nb,attr.getInteger());
+		assertEquals(nb,attr.getReal());
+		assertEquals((long)nb,attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2f(nb,0),attr.getPoint());
+		assertEquals(new Point3f(nb,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplIcon() throws Exception {
+		Image ic = VectorToolkit.image(1,1,false);
+		AttributeValue attr = new AttributeValueImpl(ic);
+		
+		assertEquals(AttributeType.IMAGE, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(ic,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertEquals(ic,attr.getImage());
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(ic.toString(), attr.getString());
+		assertEquals(ic,attr.getJavaObject());
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplInt() throws Exception {
+		int nb = new Random().nextInt();
+		String txt = Long.toString(nb);
+		AttributeValue attr = new AttributeValueImpl(nb);
+		
+		assertEquals(AttributeType.INTEGER, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(nb,((Number)attr.getValue()).intValue());
+		assertEquals(nb!=0, attr.getBoolean());
+		assertEquals(VectorToolkit.color(nb), attr.getColor());
+		assertEquals(new Date(nb),attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(nb,attr.getInteger());
+		assertEquals(nb,(int)attr.getReal());
+		assertEquals(nb,attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2f(nb,0),attr.getPoint());
+		assertEquals(new Point3f(nb,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplLong() throws Exception {
+		long nb = new Random().nextLong();
+		String txt = Long.toString(nb);
+		AttributeValue attr = new AttributeValueImpl(nb);
+		
+		assertEquals(AttributeType.INTEGER, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(nb,((Number)attr.getValue()).longValue());
+		assertEquals(nb!=0, attr.getBoolean());
+		assertEquals(VectorToolkit.color((int)nb), attr.getColor());
+		assertEquals(new Date(nb),attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(nb,attr.getInteger());
+		assertEquals((double)nb,attr.getReal());
+		assertEquals(nb,attr.getTimestamp());
+		assertEquals(txt,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2f(nb,0),attr.getPoint());
+		assertEquals(new Point3f(nb,0,0),attr.getPoint3D());
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplPoint2d() throws Exception {
+		Point2f pt = new Point2f((float)Math.random(),(float)Math.random());
+		Point3f pt3d = new Point3f(pt.getX(),pt.getY(),0);
+		String str = pt.getX()+";"+pt.getY(); //$NON-NLS-1$
+		AttributeValue attr = new AttributeValueImpl(pt);
+		
+		assertEquals(AttributeType.POINT, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(pt,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color(pt.getX(),pt.getY(),0f),attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(pt, attr.getJavaObject());
+		assertEquals(pt,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+	
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplDoubleDouble() throws Exception {
+		float x = (float)Math.random();
+		float y = (float)Math.random();
+		Point2f pt = new Point2f(x,y);
+		Point3f pt3d = new Point3f(x,y,0);
+		String str = x+";"+y; //$NON-NLS-1$
+		AttributeValue attr = new AttributeValueImpl(x,y);
+		
+		assertEquals(AttributeType.POINT, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(pt,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color(pt.getX(),pt.getY(),0f),attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(pt, attr.getJavaObject());
+		assertEquals(pt,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+	
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplPoint3d() throws Exception {
+		float x = (float)Math.random();
+		float y = (float)Math.random();
+		float z = (float)Math.random();
+		Point3f pt = new Point3f(x,y,z);
+		Point2f pt2d = new Point2f(x,y);
+		String str = x+";"+y+";"+z; //$NON-NLS-1$ //$NON-NLS-2$
+		AttributeValue attr = new AttributeValueImpl(pt);
+		
+		assertEquals(AttributeType.POINT3D, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(pt,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color(pt.getX(),pt.getY(),pt.getZ()),attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(pt, attr.getJavaObject());
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplDoubleDoubleDouble() throws Exception {
+		double x = Math.random();
+		double y = Math.random();
+		double z = Math.random();
+		Point3f pt = new Point3f(x,y,z);
+		Point2f pt2d = new Point2f(x,y);
+		String str = ((float)x)+";"+((float)y)+";"+((float)z); //$NON-NLS-1$ //$NON-NLS-2$
+		AttributeValue attr = new AttributeValueImpl(x,y,z);
+		
+		assertEquals(AttributeType.POINT3D, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(pt,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(VectorToolkit.color(pt.getX(),pt.getY(),pt.getZ()),attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertEquals(pt, attr.getJavaObject());
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_random() throws Exception {
+		double x = Math.random();
+		Point2f pt2d = new Point2f(x,0);
+		Point3f pt3d = new Point3f(x,0,0);
+		String str = Double.toHexString(x);
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertEquals(x,attr.getReal());
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_boolean() throws Exception {
+		String str = Boolean.toString(true);
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertTrue(attr.getBoolean());
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_Color() throws Exception {
+		Color c = VectorToolkit.RED;
+		Point2D pt2d = new Point2f(c.getRed(),c.getGreen());
+		Point2D pt2d2 = new Point2f(c.getBlue(),0);
+		Point3D pt3d = new Point3f(c.getRed(),c.getGreen(),c.getBlue());
+		String str = c.getRed()+";"+c.getGreen()+";"+c.getBlue();  //$NON-NLS-1$//$NON-NLS-2$
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertEquals(c,attr.getColor());
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d,pt2d2},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_Date() throws Exception {
+		Date currentDate = new Date();
+		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
+		String str = format.format(currentDate); 
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertEpsilonEquals(currentDate,attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_JDate() throws Exception {
+		Date currentDate = new Date();
+		String str = DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL).format(currentDate); 
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertEpsilonEquals(currentDate,attr.getDate());
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPolyline3D"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_Integer() throws Exception {
+		int nb = new Random().nextInt(20000)+256;
+		Point2D pt2d = new Point2f(nb,0);
+		Point3D pt3d = new Point3f(nb,0,0);
+		String str = Integer.toString(nb);
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(nb,attr.getInteger());
+		assertEquals((double)nb,attr.getReal());
+		assertEquals(nb,attr.getTimestamp());
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_Long() throws Exception {
+		long nb = new Random().nextInt(20000)+256;
+		Point2D pt2d = new Point2f(nb,0);
+		Point3D pt3d = new Point3f(nb,0,0);
+		String str = Long.toString(nb);
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertEquals(nb,attr.getInteger());
+		assertEquals((double)nb,attr.getReal());
+		assertEquals(nb,attr.getTimestamp());
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_Double() throws Exception {
+		double nb = Math.random()+256;
+		Point2D pt2d = new Point2f(nb,0);
+		Point3D pt3d = new Point3f(nb,0,0);
+		String str = Double.toString(nb);
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertEquals(nb,attr.getReal());
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_Point2D() throws Exception {
+		double x = Math.random()+256;
+		double y = Math.random()+256;
+		Point2D pt2d = new Point2f(x,y);
+		Point3D pt3d = new Point3f(x,y,0);
+		String str = x+";"+y; //$NON-NLS-1$
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplString_Point3D() throws Exception {
+		double x = Math.random()+256;
+		double y = Math.random()+256;
+		double z = Math.random()+256;
+		Point2D pt2d = new Point2f(x,y);
+		Point2D pt2d2 = new Point2f(z,0);
+		Point3D pt3d = new Point3f(x,y,z);
+		String str = x+";"+y+";"+z; //$NON-NLS-1$ //$NON-NLS-2$
+		AttributeValue attr = new AttributeValueImpl(str);
+		
+		assertEquals(AttributeType.STRING, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertTrue(attr.isBaseType());
+		assertFalse(attr.isObjectValue());
+		
+		assertEquals(str,attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertAttributeException(attr,"getJavaObject"); //$NON-NLS-1$
+		assertEquals(pt2d,attr.getPoint());
+		assertEquals(pt3d,attr.getPoint3D());
+		assertEquals(new Point2D[]{pt2d,pt2d2},attr.getPolyline());
+		assertEquals(new Point3D[]{pt3d},attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplPoint2DArray() throws Exception {
+		double x1 = Math.random();
+		double y1 = Math.random();
+		double x2 = Math.random();
+		double y2 = Math.random();
+
+		Point2D pt1 = new Point2f(x1,y1);
+		Point2D pt2 = new Point2f(x2,y2);
+		
+		Point2D[] list = new Point2D[]{ pt1, pt2 };
+		Point3D[] list2 = new Point3D[]{ new Point3f(x1,y1,0), new Point3f(x2,y2,0) };
+
+		String str = ((float)x1)+";"+((float)y1)+";"+((float)x2)+";"+((float)y2); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+		AttributeValue attr = new AttributeValueImpl(list);
+		
+		assertEquals(AttributeType.POLYLINE, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(list,(Point2D[])attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertTrue(Arrays.equals(list, (Point2D[])attr.getJavaObject()));
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertEquals(list,attr.getPolyline());
+		assertEquals(list2,attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public static void testAttributeValueImplPoint3DArray() throws Exception {
+		double x1 = Math.random();
+		double y1 = Math.random();
+		double z1 = Math.random();
+		double x2 = Math.random();
+		double y2 = Math.random();
+		double z2 = Math.random();
+
+		Point3D pt1 = new Point3f(x1,y1,z1);
+		Point3D pt2 = new Point3f(x2,y2,z2);
+		
+		Point3D[] list = new Point3D[]{ pt1, pt2 };
+		Point2D[] list2 = new Point2D[]{ new Point2f(x1,y1), new Point2f(x2,y2) };
+
+		String str = ((float)x1)+";"+((float)y1)+";"+((float)z1)+";"+((float)x2)+";"+((float)y2)+";"+((float)z2); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+
+		AttributeValue attr = new AttributeValueImpl(list);
+		
+		assertEquals(AttributeType.POLYLINE3D, attr.getType());
+
+		assertTrue(attr.isAssigned());
+		assertFalse(attr.isBaseType());
+		assertTrue(attr.isObjectValue());
+		
+		assertEquals(list,(Point3D[])attr.getValue());
+		assertAttributeException(attr,"getBoolean"); //$NON-NLS-1$
+		assertAttributeException(attr,"getColor"); //$NON-NLS-1$
+		assertAttributeException(attr,"getDate"); //$NON-NLS-1$
+		assertAttributeException(attr,"getImage"); //$NON-NLS-1$
+		assertAttributeException(attr,"getInteger"); //$NON-NLS-1$
+		assertAttributeException(attr,"getReal"); //$NON-NLS-1$
+		assertAttributeException(attr,"getTimestamp"); //$NON-NLS-1$
+		assertEquals(str,attr.getString());
+		assertTrue(Arrays.equals(list, (Point3D[])attr.getJavaObject()));
+		assertAttributeException(attr,"getPoint"); //$NON-NLS-1$
+		assertAttributeException(attr,"getPoint3D"); //$NON-NLS-1$
+		assertEquals(list2,attr.getPolyline());
+		assertEquals(list,attr.getPolyline3D());
+	}
+
+	/**
+	 * @throws AttributeException
+	 */
+	public static void testCast() throws AttributeException {
+		AttributeValue attr1, attr2;
+		String msg, str;
+		AttributeType source, target;
+		long time;
+		Color col;
+		Date dt;
+		DateFormat format;
+		Point2D pt2d;
+		Point3D pt3d;
+		
+		//
+		// SOURCE: BOOLEAN
+		//
+		
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getInteger());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getJavaObject());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,Boolean.toString((Boolean)AttributeType.BOOLEAN.getDefaultValue()), attr2.getValue());
+		assertEquals(msg,Boolean.toString((Boolean)AttributeType.BOOLEAN.getDefaultValue()), attr2.getString());
+
+		source = AttributeType.BOOLEAN;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: COLOR
+		//
+		
+		source = AttributeType.COLOR;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.COLOR;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.COLOR;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,((Color)source.getDefaultValue()).getRGB(), ((Long)attr2.getValue()).intValue());
+		assertEquals(msg,((Color)source.getDefaultValue()).getRGB(), (int)attr2.getInteger());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,VectorToolkit.color(0,0,0), attr2.getValue());
+		assertEquals(msg,VectorToolkit.color(0,0,0), attr2.getJavaObject());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,((Color)source.getDefaultValue()).getRGB(), ((Number)attr2.getValue()).intValue());
+		assertEquals(msg,((Color)source.getDefaultValue()).getRGB(), (int)attr2.getReal());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		col = (Color)source.getDefaultValue();
+		str = col.getRed()+";"+col.getGreen()+";"+col.getBlue()+";"+col.getAlpha(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		assertEquals(msg,str, attr2.getValue());
+		assertEquals(msg,str, attr2.getString());
+
+		source = AttributeType.COLOR;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: DATE
+		//
+		
+		source = AttributeType.DATE;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.DATE;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.DATE;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.DATE;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		dt = attr2.getDate();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,dt.getTime(), attr2.getValue());
+		assertEquals(msg,dt.getTime(), attr2.getInteger());
+
+		source = AttributeType.DATE;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertNotNull(msg, attr2.getValue());
+		assertNotNull(msg,attr2.getJavaObject());
+
+		source = AttributeType.DATE;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		Point2D pt = attr2.getPoint();
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,pt, attr2.getValue());
+		assertEquals(msg,pt, attr2.getPoint());
+
+		source = AttributeType.DATE;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		Point3D pt3 = attr2.getPoint3D();
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,pt3, attr2.getValue());
+		assertEquals(msg,pt3, attr2.getPoint3D());
+
+		source = AttributeType.DATE;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.DATE;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.DATE;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		dt = attr2.getDate();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,dt.getTime(), ((Double)attr2.getValue()).longValue());
+		assertEquals(msg,dt.getTime(), (long)attr2.getReal());
+
+		source = AttributeType.DATE;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		dt = (Date)source.getDefaultValue();
+		format = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$
+		str = format.format(dt);
+		assertEquals(msg,str, attr2.getValue());
+		assertEquals(msg,str, attr2.getString());
+
+		source = AttributeType.DATE;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: ICON
+		//
+		
+		source = AttributeType.IMAGE;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(),attr2.getInteger());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertNull(msg,attr2.getValue());
+		assertNull(msg,attr2.getJavaObject());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue().toString(), attr2.getString());
+
+		source = AttributeType.IMAGE;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: INTEGER
+		//
+		
+		source = AttributeType.INTEGER;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(),attr2.getInteger());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertNull(msg,attr2.getValue());
+		assertNull(msg,attr2.getJavaObject());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,"0", attr2.getValue()); //$NON-NLS-1$
+		assertEquals(msg,"0", attr2.getString()); //$NON-NLS-1$
+
+		source = AttributeType.INTEGER;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: OBJECT
+		//
+		
+		source = AttributeType.OBJECT;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertException(msg,InvalidAttributeTypeException.class, attr2,"getImage"); //$NON-NLS-1$
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertNull(msg,attr2.getValue());
+		assertNull(msg,attr2.getJavaObject());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getString());
+
+		source = AttributeType.OBJECT;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: POINT
+		//
+		
+		source = AttributeType.POINT;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.POINT;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.POINT;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.POINT;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.POINT;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(),attr2.getInteger());
+
+		source = AttributeType.POINT;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,new Point2f(), attr2.getValue());
+		assertEquals(msg,new Point2f(), attr2.getJavaObject());
+
+		source = AttributeType.POINT;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.POINT;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.POINT;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,new Point2D[] {(Point2D)source.getDefaultValue()}, (Point2D[])attr2.getValue());
+		assertEquals(msg,new Point2D[] {(Point2D)source.getDefaultValue()}, attr2.getPolyline());
+
+		source = AttributeType.POINT;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,new Point3D[] {(Point3D)AttributeType.POINT3D.getDefaultValue()}, (Point3D[])attr2.getValue());
+		assertEquals(msg,new Point3D[] {(Point3D)AttributeType.POINT3D.getDefaultValue()}, attr2.getPolyline3D());
+
+		source = AttributeType.POINT;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.POINT;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		pt2d = (Point2D)source.getDefaultValue();
+		str = pt2d.getX()+";"+pt2d.getY(); //$NON-NLS-1$
+		assertEquals(msg,str, attr2.getValue());
+		assertEquals(msg,str, attr2.getString());
+
+		source = AttributeType.POINT;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: POINT3D
+		//
+		
+		source = AttributeType.POINT3D;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(),attr2.getInteger());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,new Point3f(), attr2.getValue());
+		assertEquals(msg,new Point3f(), attr2.getJavaObject());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,new Point2D[] {(Point2D)AttributeType.POINT.getDefaultValue()}, (Point2D[])attr2.getValue());
+		assertEquals(msg,new Point2D[] {(Point2D)AttributeType.POINT.getDefaultValue()}, attr2.getPolyline());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,new Point3D[] {(Point3D)AttributeType.POINT3D.getDefaultValue()}, (Point3D[])attr2.getValue());
+		assertEquals(msg,new Point3D[] {(Point3D)AttributeType.POINT3D.getDefaultValue()}, attr2.getPolyline3D());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		pt3d = (Point3D)source.getDefaultValue();
+		str = pt2d.getX()+";"+pt2d.getY()+";"+pt3d.getZ(); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(msg,str, attr2.getValue());
+		assertEquals(msg,str, attr2.getString());
+
+		source = AttributeType.POINT3D;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: POLYLINE
+		//
+		
+		source = AttributeType.POLYLINE;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(),attr2.getInteger());
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,Arrays.equals(new Point2f[0], (Point2D[])attr2.getValue()));
+		assertTrue(msg,Arrays.equals(new Point2f[0], (Point2D[])attr2.getJavaObject()));
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])source.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])source.getDefaultValue(), attr2.getPolyline());
+		
+		source = AttributeType.POLYLINE;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])AttributeType.POLYLINE3D.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])AttributeType.POLYLINE3D.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		str = ""; //$NON-NLS-1$
+		assertEquals(msg,str, attr2.getValue());
+		assertEquals(msg,str, attr2.getString());
+
+		source = AttributeType.POLYLINE;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: POLYLINE3D
+		//
+		
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(),attr2.getInteger());
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,Arrays.equals(new Point3f[0], (Point3D[])attr2.getValue()));
+		assertTrue(msg,Arrays.equals(new Point3f[0], (Point3D[])attr2.getJavaObject()));
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])AttributeType.POLYLINE.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])AttributeType.POLYLINE.getDefaultValue(), attr2.getPolyline());
+		
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])AttributeType.POLYLINE3D.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])AttributeType.POLYLINE3D.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		str = ""; //$NON-NLS-1$
+		assertEquals(msg,str, attr2.getValue());
+		assertEquals(msg,str, attr2.getString());
+
+		source = AttributeType.POLYLINE3D;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: REAL
+		//
+		
+		source = AttributeType.REAL;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.REAL;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.REAL;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.REAL;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.REAL;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(),attr2.getInteger());
+
+		source = AttributeType.REAL;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertNull(msg,attr2.getValue());
+		assertNull(msg,attr2.getJavaObject());
+
+		source = AttributeType.REAL;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.REAL;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.REAL;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.REAL;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.REAL;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.REAL;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,Double.toString(0), attr2.getValue());
+		assertEquals(msg,Double.toString(0), attr2.getString());
+
+		source = AttributeType.REAL;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: STRING
+		//
+		
+		source = AttributeType.STRING;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getBoolean());
+
+		source = AttributeType.STRING;
+		target = AttributeType.COLOR;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getColor());
+
+		source = AttributeType.STRING;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.STRING;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.STRING;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(),attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(),attr2.getInteger());
+
+		source = AttributeType.STRING;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertNull(msg,attr2.getValue());
+		assertNull(msg,attr2.getJavaObject());
+
+		source = AttributeType.STRING;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint());
+
+		source = AttributeType.STRING;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getPoint3D());
+
+		source = AttributeType.STRING;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.STRING;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.STRING;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertEquals(msg,target.getDefaultValue(), attr2.getReal());
+
+		source = AttributeType.STRING;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		str = ""; //$NON-NLS-1$
+		assertEquals(msg,str, attr2.getValue());
+		assertEquals(msg,str, attr2.getString());
+
+		source = AttributeType.STRING;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		//
+		// SOURCE: TIMESTAMP
+		//
+		
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.BOOLEAN;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,true, attr2.getValue());
+		assertEquals(msg,true, attr2.getBoolean());
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.DATE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Date)attr2.getValue()).getTime()<=time);
+		assertTrue(msg,attr2.getDate().getTime()<=time);
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.IMAGE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,target.getDefaultValue(), attr2.getValue());
+		assertException(msg, AttributeNotInitializedException.class, attr2, "getImage"); //$NON-NLS-1$
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.INTEGER;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		time = System.currentTimeMillis();
+		assertTrue(msg,(Long)attr2.getValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.OBJECT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertNull(msg,attr2.getValue());
+		assertNull(msg,attr2.getJavaObject());
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.POINT;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		time = attr2.getTimestamp();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,new Point2f(time,0), attr2.getValue());
+		assertEquals(msg,new Point2f(time,0), attr2.getPoint());
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.POINT3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		time = attr2.getTimestamp();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,new Point3f(time,0,0), attr2.getValue());
+		assertEquals(msg,new Point3f(time,0,0), attr2.getPoint3D());
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.POLYLINE;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), (Point2D[])attr2.getValue());
+		assertEquals(msg,(Point2D[])target.getDefaultValue(), attr2.getPolyline());
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.POLYLINE3D;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), (Point3D[])attr2.getValue());
+		assertEquals(msg,(Point3D[])target.getDefaultValue(), attr2.getPolyline3D());
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.REAL;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		time = attr2.getTimestamp();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertEquals(msg,Double.valueOf(time), attr2.getValue());
+		assertEquals(msg,Long.valueOf(time).doubleValue(), attr2.getReal());
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.STRING;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();
+		time = attr2.getTimestamp();
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$
+		str = format.format(new Date(time));
+		assertEquals(msg,str, attr2.getValue());
+		assertEquals(msg,str, attr2.getString());
+
+		source = AttributeType.TIMESTAMP;
+		target = AttributeType.TIMESTAMP;
+		msg = "from '"+source.toString()+"' to '"+target.toString()+"'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		attr1 = new AttributeValueImpl(source);
+		attr2 = new AttributeValueImpl(source);
+		attr2.setToDefault();		
+		attr1.cast(target);
+		assertFalse(msg,attr1.isAssigned());
+		attr2.cast(target);
+		assertTrue(msg,attr2.isAssigned());
+		assertTrue(msg,attr2.getValue() instanceof Timestamp);
+		time = System.currentTimeMillis();
+		assertTrue(msg,((Number)attr2.getValue()).longValue()<=time);
+		assertTrue(msg,attr2.getTimestamp()<=time);
+
+	}
+	
+	/**
+	 */
+	public static void testEquals() {
+		AttributeValueImpl attr = new AttributeValueImpl();
+		
+		attr.setBoolean(true);
+		assertTrue(attr.equals(new AttributeValueImpl(true)));
+		assertFalse(attr.equals(new AttributeValueImpl(false)));
+		assertTrue(attr.equals(true));
+		assertFalse(attr.equals(false));
+		assertTrue(attr.equals(new AttributeValueImpl("true"))); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeValueImpl("false"))); //$NON-NLS-1$
+		assertTrue(attr.equals("true")); //$NON-NLS-1$
+		assertFalse(attr.equals("false")); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeValueImpl(1.)));
+		assertFalse(attr.equals(new AttributeValueImpl("1."))); //$NON-NLS-1$
+		assertFalse(attr.equals(1.));
+		assertFalse(attr.equals("toto")); //$NON-NLS-1$
+
+		attr.setBoolean(false);
+		assertFalse(attr.equals(new AttributeValueImpl(true)));
+		assertTrue(attr.equals(new AttributeValueImpl(false)));
+		assertFalse(attr.equals(true));
+		assertTrue(attr.equals(false));
+		assertFalse(attr.equals(new AttributeValueImpl("true"))); //$NON-NLS-1$
+		assertTrue(attr.equals(new AttributeValueImpl("false"))); //$NON-NLS-1$
+		assertFalse(attr.equals("true")); //$NON-NLS-1$
+		assertTrue(attr.equals("false")); //$NON-NLS-1$
+		assertFalse(attr.equals(new AttributeValueImpl(1.)));
+		assertFalse(attr.equals(new AttributeValueImpl("1."))); //$NON-NLS-1$
+		assertFalse(attr.equals(1.));
+		assertFalse(attr.equals("toto")); //$NON-NLS-1$
+	}
+	
+	/** 
+	 */
+	public static void testParse() {
+		AttributeValueImpl v;
+		
+		v = AttributeValueImpl.parse("127.0.0.1"); //$NON-NLS-1$
+		assertSame(AttributeType.INET_ADDRESS, v.getType());
+
+		v = AttributeValueImpl.parse("localhost"); //$NON-NLS-1$
+		assertSame(AttributeType.INET_ADDRESS, v.getType());
+
+		v = AttributeValueImpl.parse("java.lang.String"); //$NON-NLS-1$
+		assertSame(AttributeType.TYPE, v.getType());
+
+		v = AttributeValueImpl.parse(AttributeType.class.getName()+"."+AttributeType.ENUMERATION.toString()); //$NON-NLS-1$
+		assertSame(AttributeType.ENUMERATION, v.getType());
+
+		v = AttributeValueImpl.parse("3eade434-b267-4ffa-a574-2e2cbff0151a"); //$NON-NLS-1$
+		assertSame(AttributeType.UUID, v.getType());
+
+		v = AttributeValueImpl.parse("134"); //$NON-NLS-1$
+		assertSame(AttributeType.INTEGER, v.getType());
+
+		v = AttributeValueImpl.parse("-134"); //$NON-NLS-1$
+		assertSame(AttributeType.INTEGER, v.getType());
+
+		v = AttributeValueImpl.parse("134e34"); //$NON-NLS-1$
+		assertSame(AttributeType.REAL, v.getType());
+
+		v = AttributeValueImpl.parse("-134.5"); //$NON-NLS-1$
+		assertSame(AttributeType.REAL, v.getType());
+
+		v = AttributeValueImpl.parse("2012-11-30 18:22:34"); //$NON-NLS-1$
+		assertSame(AttributeType.DATE, v.getType());
+
+		v = AttributeValueImpl.parse("Fri, 30 Nov 2012 18:22:42 +0100"); //$NON-NLS-1$
+		assertSame(AttributeType.DATE, v.getType());
+
+		v = AttributeValueImpl.parse("True"); //$NON-NLS-1$
+		assertSame(AttributeType.BOOLEAN, v.getType());
+		
+		v = AttributeValueImpl.parse("False"); //$NON-NLS-1$
+		assertSame(AttributeType.BOOLEAN, v.getType());
+
+		v = AttributeValueImpl.parse("TrUe"); //$NON-NLS-1$
+		assertSame(AttributeType.BOOLEAN, v.getType());
+
+		v = AttributeValueImpl.parse("http://www.multiagent.fr";); //$NON-NLS-1$
+		assertSame(AttributeType.URL, v.getType());
+
+		v = AttributeValueImpl.parse("mailto:stephane.galland@xxxxxxx";); //$NON-NLS-1$
+		assertSame(AttributeType.URL, v.getType());
+
+		v = AttributeValueImpl.parse("urn:isbn:096139210x"); //$NON-NLS-1$
+		assertSame(AttributeType.URI, v.getType());
+
+		v = AttributeValueImpl.parse("1;2;3;4;5;6;7;8;9"); //$NON-NLS-1$
+		assertSame(AttributeType.POLYLINE3D, v.getType());
+
+		v = AttributeValueImpl.parse("1;2;3;4;5;6;7;8"); //$NON-NLS-1$
+		assertSame(AttributeType.POLYLINE, v.getType());
+
+		v = AttributeValueImpl.parse("1;2;3;4"); //$NON-NLS-1$
+		assertSame(AttributeType.COLOR, v.getType());
+
+		v = AttributeValueImpl.parse("1;2;3"); //$NON-NLS-1$
+		assertSame(AttributeType.COLOR, v.getType());
+
+		v = AttributeValueImpl.parse("1;2;300"); //$NON-NLS-1$
+		assertSame(AttributeType.POINT3D, v.getType());
+
+		v = AttributeValueImpl.parse("1;2"); //$NON-NLS-1$
+		assertSame(AttributeType.POINT, v.getType());
+
+		v = AttributeValueImpl.parse("blablabla"); //$NON-NLS-1$
+		assertSame(AttributeType.STRING, v.getType());
+	}
+
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractAttributeCollectionTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractAttributeCollectionTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractAttributeCollectionTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,601 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.attrs.collection.AttributeChangeEvent;
+import org.arakhne.afc.attrs.collection.AttributeChangeListener;
+import org.arakhne.afc.attrs.collection.AttributeCollection;
+
+/**
+ * Test of AbstractAttributeProvider.
+ * 
+ * @param <T>
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class AbstractAttributeCollectionTest<T extends AttributeCollection> extends AbstractAttributeProviderTest<T> {
+
+	private Attribute[] newValues;
+	
+	/**
+	 */
+	protected ListenerStub listenerStub;
+	
+	/**
+	 * @param id
+	 */
+	public AbstractAttributeCollectionTest(String id) {
+		super(id);
+	}
+	
+	@Override
+	public void setUp() throws Exception {
+		super.setUp();
+		
+		this.newValues = new Attribute[] {
+			new AttributeImpl("A",false),	 //$NON-NLS-1$
+			new AttributeImpl("D","34"),	 //$NON-NLS-1$ //$NON-NLS-2$
+			new AttributeImpl("Z",17f),	 //$NON-NLS-1$
+		};
+		
+		this.listenerStub = new ListenerStub();
+		this.testData.addAttributeChangeListener(this.listenerStub);
+	}
+	
+	@Override
+	public void tearDown() throws Exception {
+		this.newValues = null;
+		this.listenerStub.reset();
+		this.listenerStub = null;
+		super.tearDown();
+	}
+	
+	private void runSetAttributeValue(Class<?>[] types, Object[] parameters, Attribute attr) throws Exception {
+		String name = attr.getName();
+		
+		boolean attrExists = this.testData.hasAttribute(name);
+		AttributeValue oldValue = null;
+		if (attrExists) {
+			oldValue = this.testData.getAttribute(name);
+		}
+	
+		Method method = this.testData.getClass().getMethod("setAttribute", types); //$NON-NLS-1$
+		Object o = method.invoke(this.testData, parameters);
+
+		assertTrue(this.id, o instanceof Attribute);
+		assertEquals(this.id, attr,o);
+		
+		assertNotNull(this.id, this.testData.getAttribute(name));
+		assertEquals(this.id, attr.getType(),this.testData.getAttribute(name).getType());
+		assertEquals(this.id, attr,this.testData.getAttribute(name));
+		
+		// Test events
+		String message = this.id+": set attribute "+name; //$NON-NLS-1$
+		this.listenerStub.assertNames(message, name);
+		this.listenerStub.assertValues(message, attr);
+		if (!attrExists) {
+			this.listenerStub.assertTypes(message,
+					AttributeChangeEvent.Type.ADDITION);
+			this.listenerStub.assertOldNames(message, new String[]{null});
+			this.listenerStub.assertOldValues(message, new AttributeValue[]{null});
+		}
+		else {
+			this.listenerStub.assertTypes(message,
+					AttributeChangeEvent.Type.VALUE_UPDATE);
+			this.listenerStub.assertOldNames(message, name);
+			this.listenerStub.assertOldValues(message, oldValue);
+		}
+		
+		this.listenerStub.reset();
+	}
+	
+	private void runSetAttributeValue(Class<?> type, Object parameter, Attribute attr) throws Exception {
+		runSetAttributeValue(
+				new Class<?>[] {String.class, type},
+				new Object[] {attr.getName(), parameter}, attr);
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeAttribute() throws Exception {
+		for (Attribute attr : this.newValues) {
+			runSetAttributeValue(
+					new Class<?>[] {Attribute.class},
+					new Object[] {attr},
+					attr);
+		}
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeStringAttributeValue() throws Exception {
+		for (Attribute attr : this.newValues) {
+			runSetAttributeValue(
+					AttributeValue.class,
+					attr,
+					attr);
+		}
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeStringBoolean() throws Exception {
+		Attribute attr = new AttributeImpl("A", false); //$NON-NLS-1$
+		runSetAttributeValue(
+				boolean.class,
+				attr.getBoolean(),
+				attr);
+		attr = new AttributeImpl("X", false); //$NON-NLS-1$
+		runSetAttributeValue(
+				boolean.class,
+				attr.getBoolean(),
+				attr);
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeStringInt() throws Exception {
+		Attribute attr = new AttributeImpl("E", 34); //$NON-NLS-1$
+		runSetAttributeValue(
+				int.class,
+				(int)attr.getInteger(),
+				attr);
+		attr = new AttributeImpl("X", 34); //$NON-NLS-1$
+		runSetAttributeValue(
+				int.class,
+				(int)attr.getInteger(),
+				attr);
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeStringLong() throws Exception {
+		Attribute attr = new AttributeImpl("E", 34); //$NON-NLS-1$
+		runSetAttributeValue(
+				long.class,
+				attr.getInteger(),
+				attr);
+		attr = new AttributeImpl("X", 34); //$NON-NLS-1$
+		runSetAttributeValue(
+				long.class,
+				attr.getInteger(),
+				attr);
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeStringFloat() throws Exception {
+		Attribute attr = new AttributeImpl("E", 34f); //$NON-NLS-1$
+		runSetAttributeValue(
+				float.class,
+				(float)attr.getReal(),
+				attr);
+		attr = new AttributeImpl("X", 34f); //$NON-NLS-1$
+		runSetAttributeValue(
+				float.class,
+				(float)attr.getReal(),
+				attr);
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeStringDouble() throws Exception {
+		Attribute attr = new AttributeImpl("E", 34.); //$NON-NLS-1$
+		runSetAttributeValue(
+				double.class,
+				attr.getReal(),
+				attr);
+		attr = new AttributeImpl("X", 34.); //$NON-NLS-1$
+		runSetAttributeValue(
+				double.class,
+				attr.getReal(),
+				attr);
+	}
+	
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeStringString() throws Exception {
+		Attribute attr = new AttributeImpl("E", "Toto"); //$NON-NLS-1$ //$NON-NLS-2$
+		runSetAttributeValue(
+				String.class,
+				attr.getString(),
+				attr);
+		attr = new AttributeImpl("X", "Titi et Rominet"); //$NON-NLS-1$ //$NON-NLS-2$
+		runSetAttributeValue(
+				String.class,
+				attr.getString(),
+				attr);
+	}
+
+	/**
+	 */
+	public void testRemoveAttributeString() {
+		String message;
+		
+		assertFalse(this.id, this.testData.removeAttribute("Y")); //$NON-NLS-1$
+		// Testing events
+		message = this.id+": removing Y"; //$NON-NLS-1$
+		this.listenerStub.assertEmpty(message);
+		this.listenerStub.reset();
+		
+		assertTrue(this.id, this.testData.removeAttribute("C")); //$NON-NLS-1$
+		// Testing events
+		message = "removing C"; //$NON-NLS-1$
+		this.listenerStub.assertTypes(message, AttributeChangeEvent.Type.REMOVAL);
+		this.listenerStub.assertNames(message, "C"); //$NON-NLS-1$
+		this.listenerStub.assertOldNames(message, "C"); //$NON-NLS-1$
+		this.listenerStub.assertValues(message, new AttributeValueImpl(true));
+		this.listenerStub.assertOldValues(message, new AttributeValueImpl(true));
+		this.listenerStub.reset();
+
+		assertFalse(this.id, this.testData.removeAttribute("X")); //$NON-NLS-1$
+		// Testing events
+		message = this.id+": removing X"; //$NON-NLS-1$
+		this.listenerStub.assertEmpty(message);
+		this.listenerStub.reset();
+		
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+	}
+
+	/**
+	 */
+	public void testRemoveAllAttributes() {
+		String message;
+		
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+
+		assertTrue(this.id, this.testData.removeAllAttributes());
+		message = this.id+": removing all attributes"; //$NON-NLS-1$
+		this.listenerStub.assertTypes(message, AttributeChangeEvent.Type.REMOVE_ALL);
+		this.listenerStub.assertNames(message, new String[]{null});
+		this.listenerStub.assertOldNames(message, new String[]{null});
+		this.listenerStub.assertValues(message, new AttributeValue[]{null});
+		this.listenerStub.assertOldValues(message, new AttributeValue[]{null});
+		this.listenerStub.reset();
+
+		assertFalse(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+
+		assertFalse(this.id, this.testData.removeAllAttributes());
+		this.listenerStub.assertEmpty(message);
+		this.listenerStub.reset();
+
+		assertFalse(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+	}
+	
+	/**
+	 */
+	public void testRenameAttribute() {
+		String message;
+		
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+		AttributeValue oldValue = this.testData.getAttribute("B"); //$NON-NLS-1$
+
+		assertTrue(this.id, this.testData.renameAttribute("B", "ZZZ", false)); //$NON-NLS-1$ //$NON-NLS-2$
+		// Testing events
+		message = this.id+": renaming B to ZZZ"; //$NON-NLS-1$
+		this.listenerStub.assertTypes(message, AttributeChangeEvent.Type.RENAME);
+		this.listenerStub.assertNames(message, "ZZZ"); //$NON-NLS-1$
+		this.listenerStub.assertOldNames(message, "B"); //$NON-NLS-1$
+		this.listenerStub.assertValues(message, oldValue);
+		this.listenerStub.assertOldValues(message, oldValue);
+		this.listenerStub.reset();
+
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("ZZZ")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+		assertEquals(this.id, oldValue, this.testData.getAttribute("ZZZ")); //$NON-NLS-1$
+
+		assertFalse(this.id, this.testData.renameAttribute("toto", "XXX", false)); //$NON-NLS-1$ //$NON-NLS-2$
+		// Testing events
+		message = this.id+": renaming toto to XXX"; //$NON-NLS-1$
+		this.listenerStub.assertEmpty(message);
+		this.listenerStub.reset();
+
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("ZZZ")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+		oldValue = this.testData.getAttribute("F"); //$NON-NLS-1$
+		AttributeValue oldValue2 = this.testData.getAttribute("A"); //$NON-NLS-1$
+
+		assertFalse(this.id, this.testData.renameAttribute("F", "A", false)); //$NON-NLS-1$ //$NON-NLS-2$
+		// Testing events
+		message = this.id+": renaming F to A"; //$NON-NLS-1$
+		this.listenerStub.assertEmpty(message);
+		this.listenerStub.reset();
+
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("ZZZ")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+		assertEquals(this.id, oldValue, this.testData.getAttribute("F")); //$NON-NLS-1$
+		assertEquals(this.id, oldValue2, this.testData.getAttribute("A")); //$NON-NLS-1$
+	}
+	
+	/**
+	 */
+	public void testRenameAttributeOverwrite() {
+		String message;
+		
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+		AttributeValue oldValue = this.testData.getAttribute("B"); //$NON-NLS-1$
+
+		assertTrue(this.id, this.testData.renameAttribute("B", "ZZZ", true)); //$NON-NLS-1$ //$NON-NLS-2$
+		// Testing events
+		message = this.id+": renaming B to ZZZ"; //$NON-NLS-1$
+		this.listenerStub.assertTypes(message, AttributeChangeEvent.Type.RENAME);
+		this.listenerStub.assertNames(message, "ZZZ"); //$NON-NLS-1$
+		this.listenerStub.assertOldNames(message, "B"); //$NON-NLS-1$
+		this.listenerStub.assertValues(message, oldValue);
+		this.listenerStub.assertOldValues(message, oldValue);
+		this.listenerStub.reset();
+
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("ZZZ")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+		assertEquals(this.id, oldValue, this.testData.getAttribute("ZZZ")); //$NON-NLS-1$
+
+		assertFalse(this.id, this.testData.renameAttribute("toto", "XXX", true)); //$NON-NLS-1$ //$NON-NLS-2$
+		// Testing events
+		message = this.id+": renaming toto to XXX"; //$NON-NLS-1$
+		this.listenerStub.assertEmpty(message);
+		this.listenerStub.reset();
+
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("ZZZ")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+		oldValue = this.testData.getAttribute("F"); //$NON-NLS-1$
+		AttributeValue oldValue2 = this.testData.getAttribute("A"); //$NON-NLS-1$
+
+		assertTrue(this.id, this.testData.renameAttribute("F", "A", true)); //$NON-NLS-1$ //$NON-NLS-2$
+		// Testing events
+		message = this.id+": renaming F to A"; //$NON-NLS-1$
+		this.listenerStub.assertTypes(message, AttributeChangeEvent.Type.REMOVAL, AttributeChangeEvent.Type.RENAME);
+		this.listenerStub.assertNames(message, "A","A"); //$NON-NLS-1$ //$NON-NLS-2$
+		this.listenerStub.assertOldNames(message, "A", "F"); //$NON-NLS-1$ //$NON-NLS-2$
+		this.listenerStub.assertValues(message, oldValue2, oldValue);
+		this.listenerStub.assertOldValues(message, oldValue2, oldValue);
+		this.listenerStub.reset();
+
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("ZZZ")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+		
+		assertEquals(this.id, oldValue, this.testData.getAttribute("A")); //$NON-NLS-1$
+	}
+	
+	/**
+	 * Stub for AttributeChangeListener.
+	 * 
+	 * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	protected class ListenerStub implements AttributeChangeListener {
+
+		private final ArrayList<AttributeChangeEvent> eventList = new ArrayList<AttributeChangeEvent>();
+
+		/**
+		 */
+		public void reset() {
+			this.eventList.clear();
+		}
+		
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public void onAttributeChangeEvent(AttributeChangeEvent event) {
+			this.eventList.add(event);
+		}
+		
+		/**
+		 * @param message
+		 */
+		public void assertEmpty(String message) {
+			assertEquals(message, 0,this.eventList.size());
+		}
+
+		/**
+		 * @param message
+		 * @param desiredTypes
+		 */
+		public void assertTypes(String message, AttributeChangeEvent.Type... desiredTypes) {
+			assertEquals(message, desiredTypes.length, this.eventList.size());
+			for(int i=0; i<desiredTypes.length; ++i) {
+				assertEquals(message+" at index "+i, desiredTypes[i], this.eventList.get(i).getType()); //$NON-NLS-1$
+			}
+		}
+
+		/**
+		 * @param message
+		 * @param desiredNames
+		 */
+		public void assertNames(String message, String... desiredNames) {
+			assertEquals(message, desiredNames.length, this.eventList.size());
+			for(int i=0; i<desiredNames.length; ++i) {
+				assertEquals(message+" at index "+i, desiredNames[i], this.eventList.get(i).getName()); //$NON-NLS-1$
+			}
+		}
+
+		/**
+		 * @param message
+		 * @param desiredNames
+		 */
+		public void assertOldNames(String message, String... desiredNames) {
+			assertEquals(message, desiredNames.length, this.eventList.size());
+			for(int i=0; i<desiredNames.length; ++i) {
+				assertEquals(message+" at index "+i, desiredNames[i], this.eventList.get(i).getOldName()); //$NON-NLS-1$
+			}
+		}
+
+		/**
+		 * @param message
+		 * @param desiredValues
+		 */
+		public void assertValues(String message, AttributeValue... desiredValues) {
+			assertEquals(message, desiredValues.length, this.eventList.size());
+			for(int i=0; i<desiredValues.length; ++i) {
+				assertEquals(message+" at index "+i, desiredValues[i], this.eventList.get(i).getValue()); //$NON-NLS-1$
+			}
+		}
+
+		/**
+		 * @param message
+		 * @param desiredValues
+		 */
+		public void assertOldValues(String message, AttributeValue... desiredValues) {
+			assertEquals(message, desiredValues.length, this.eventList.size());
+			for(int i=0; i<desiredValues.length; ++i) {
+				assertEquals(message+" at index "+i, desiredValues[i], this.eventList.get(i).getOldValue()); //$NON-NLS-1$
+			}
+		}
+
+		/**
+		 * @param message
+		 * @param desiredAttributes
+		 */
+		public void assertAttributes(String message, Attribute... desiredAttributes) {
+			assertEquals(message, desiredAttributes.length, this.eventList.size());
+			for(int i=0; i<desiredAttributes.length; ++i) {
+				assertEquals(message+" at index "+i, desiredAttributes[i], this.eventList.get(i).getAttribute()); //$NON-NLS-1$
+			}
+		}
+
+	}
+
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractAttributeProviderTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractAttributeProviderTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractAttributeProviderTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,436 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.arakhne.afc.attrs.AbstractAttrTestCase;
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.attrs.attr.InvalidAttributeTypeException;
+import org.arakhne.afc.attrs.collection.AttributeCollection;
+import org.arakhne.afc.attrs.collection.AttributeProvider;
+import org.arakhne.afc.math.continous.object2d.Point2f;
+
+/**
+ * Test of AbstractAttributeContainer.
+ * 
+ * @param <T>
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class AbstractAttributeProviderTest<T extends AttributeProvider> extends AbstractAttrTestCase {
+
+	/**
+	 */
+	protected final String id;
+	
+	/**
+	 * @param id
+	 */
+	public AbstractAttributeProviderTest(String id) {
+		super();
+		this.id = id;
+	}
+	
+	/**
+	 * Assertion on invalid value exception.
+	 * 
+	 * @param provider
+	 * @param methodName
+	 * @param parameters
+	 * @throws Exception
+	 */
+	protected static void assertInvalidValue(AttributeProvider provider, String methodName, Object... parameters) throws Exception {
+		assertInvalidValue(null, provider, methodName, parameters);
+	}
+
+	/**
+	 * Assertion on invalid value exception.
+	 * 
+	 * @param message
+	 * @param provider
+	 * @param methodName
+	 * @param parameters
+	 * @throws Exception
+	 */
+	protected static void assertInvalidValue(String message, AttributeProvider provider, String methodName, Object... parameters) throws Exception {
+		StringBuilder msg = new StringBuilder();
+		if (message!=null && !message.isEmpty()) msg.append(": "); //$NON-NLS-1$
+		try {
+			Class<?>[] classTab = new Class<?>[parameters.length];
+			for(int i=0; i<parameters.length; ++i) {
+				classTab[i] = parameters[i].getClass();
+			}
+			Class<? extends AttributeProvider> clazz = provider.getClass();
+			Method method = clazz.getMethod(methodName,classTab);
+			method.invoke(provider,parameters);
+			msg.append("the exception InvalidAttributeTypeException was not thrown: standard return from the function "); //$NON-NLS-1$
+			msg.append(methodName);
+			fail(msg.toString());
+		}
+		catch(InvocationTargetException e) {
+			Throwable ex = e.getTargetException();
+			if (ex instanceof InvalidAttributeTypeException) {
+				// normal case
+			}
+			else {
+				msg.append("the exception InvalidAttributeTypeException was not thrown, exception: "); //$NON-NLS-1$
+				msg.append(ex);
+				msg.append(", file: "); //$NON-NLS-1$
+				msg.append(ex.getStackTrace()[0].getFileName());
+				msg.append(", line: "); //$NON-NLS-1$
+				msg.append(ex.getStackTrace()[0].getLineNumber());
+				fail(msg.toString());
+			}
+		}
+	}	
+	
+	/**
+	 */
+	protected T testData;
+	
+	/**
+	 */
+	protected Attribute[] baseData;
+
+	/**
+	 * Fill the attribute provider with test case data.
+	 * 
+	 * @param provider
+	 * @throws AttributeException
+	 */
+	protected void createTestCaseData(AttributeCollection provider) throws AttributeException {
+		for (Attribute a : this.baseData) {
+			provider.setAttribute(a);
+		}
+	}
+	
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.baseData = new Attribute[] {
+				new AttributeImpl("A",1), //$NON-NLS-1$
+				new AttributeImpl("B",2.), //$NON-NLS-1$
+				new AttributeImpl("C",true), //$NON-NLS-1$
+				new AttributeImpl("D","Hello"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E",new Point2f(1,2)), //$NON-NLS-1$
+				new AttributeImpl("F","false"), //$NON-NLS-1$ //$NON-NLS-2$
+		};
+		this.testData = setUpTestCase();
+		if (this.testData instanceof AttributeCollection) {
+			createTestCaseData((AttributeCollection)this.testData);
+		}
+	}
+
+	/** Initialize the test case.
+	 * @return the set up test case.
+	 * @throws Exception
+	 */
+	protected abstract T setUpTestCase() throws Exception;
+
+	@Override
+	protected void tearDown() throws Exception {
+		this.testData = null;
+		this.baseData = null;
+		super.tearDown();
+	}
+
+	/**
+	 */
+	public void testIterator() {
+		ArrayList<Attribute> ref = new ArrayList<Attribute>();
+		ref.addAll(Arrays.asList(this.baseData));
+
+		Iterator<Attribute> it = this.testData.attributes().iterator();
+		while(!ref.isEmpty()) {
+			assertTrue(this.id, it.hasNext());
+			Attribute attr = it.next();
+			assertNotNull(this.id, attr);
+			assertTrue(this.id, ref.remove(attr));
+		}
+		
+		assertFalse(this.id, it.hasNext());
+	}
+
+	/**
+	 */
+	public void testHasAttribute() {
+		assertTrue(this.id, this.testData.hasAttribute("A")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("X")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("B")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Y")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("D")); //$NON-NLS-1$
+		assertFalse(this.id, this.testData.hasAttribute("Z")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("E")); //$NON-NLS-1$
+		assertTrue(this.id, this.testData.hasAttribute("F")); //$NON-NLS-1$
+	}
+
+	/**
+	 */
+	public void testGetAllAttributes() {
+		assertEpsilonEquals(this.id, this.baseData, this.testData.getAllAttributes().toArray());
+	}
+
+	/**
+	 */
+	public void testGetAllAttributesByType() {
+		HashMap<AttributeType,Collection<Attribute>> map = new HashMap<AttributeType,Collection<Attribute>>();
+		for(Attribute data : this.baseData) {
+			AttributeType type = data.getType();
+			Collection<Attribute> col = map.get(type);
+			if (col==null) {
+				col = new ArrayList<Attribute>();
+				map.put(type,col);
+			}
+			col.add(data);
+		}
+		
+		assertEquals(this.id, map, this.testData.getAllAttributesByType());
+	}
+
+
+	/**
+	 */
+	public void testGetAllAttributeNames() {
+		assertEpsilonEquals(this.id, new String[] {
+				"A", //$NON-NLS-1$
+				"B", //$NON-NLS-1$
+				"C", //$NON-NLS-1$
+				"D", //$NON-NLS-1$
+				"E", //$NON-NLS-1$
+				"F", //$NON-NLS-1$
+		}, this.testData.getAllAttributeNames().toArray());
+	}
+
+	/**
+	 */
+	public void testGetAttributeString() {
+		assertEquals(this.id, this.baseData[0],this.testData.getAttribute("A")); //$NON-NLS-1$
+		assertNull(this.id, this.testData.getAttribute("X")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[1],this.testData.getAttribute("B")); //$NON-NLS-1$
+		assertNull(this.id, this.testData.getAttribute("Y")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[2],this.testData.getAttribute("C")); //$NON-NLS-1$
+		assertNull(this.id, this.testData.getAttribute("Z")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[3],this.testData.getAttribute("D")); //$NON-NLS-1$
+		assertNull(this.id, this.testData.getAttribute("W")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[4],this.testData.getAttribute("E")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[5],this.testData.getAttribute("F")); //$NON-NLS-1$
+	}
+
+	/**
+	 */
+	public void testGetAttributeStringAttributeValue() {
+		AttributeValue defaultValue = new AttributeValueImpl();
+		assertEquals(this.id, this.baseData[0],this.testData.getAttribute("A",defaultValue)); //$NON-NLS-1$
+		assertSame(this.id, defaultValue, this.testData.getAttribute("X", defaultValue)); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[1],this.testData.getAttribute("B", defaultValue)); //$NON-NLS-1$
+		assertSame(this.id, defaultValue, this.testData.getAttribute("Y", defaultValue)); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[2],this.testData.getAttribute("C", defaultValue)); //$NON-NLS-1$
+		assertSame(this.id, defaultValue, this.testData.getAttribute("Z", defaultValue)); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[3],this.testData.getAttribute("D", defaultValue)); //$NON-NLS-1$
+		assertSame(this.id, defaultValue, this.testData.getAttribute("W", defaultValue)); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[4],this.testData.getAttribute("E", defaultValue)); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[5],this.testData.getAttribute("F", defaultValue)); //$NON-NLS-1$
+	}
+
+	/**
+	 */
+	public void testGetAttributeObject() {
+		assertEquals(this.id, this.baseData[0],this.testData.getAttributeObject("A")); //$NON-NLS-1$
+		assertNull(this.id, this.testData.getAttribute("X")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[1],this.testData.getAttributeObject("B")); //$NON-NLS-1$
+		assertNull(this.id, this.testData.getAttribute("Y")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[2],this.testData.getAttributeObject("C")); //$NON-NLS-1$
+		assertNull(this.id, this.testData.getAttribute("Z")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[3],this.testData.getAttributeObject("D")); //$NON-NLS-1$
+		assertNull(this.id, this.testData.getAttribute("W")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[4],this.testData.getAttributeObject("E")); //$NON-NLS-1$
+		assertEquals(this.id, this.baseData[5],this.testData.getAttributeObject("F")); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeAsBoolString() throws Exception {
+		assertTrue(this.id, this.testData.getAttributeAsBool("A"));//$NON-NLS-1$
+		assertTrue(this.id, this.testData.getAttributeAsBool("B"));//$NON-NLS-1$
+		assertTrue(this.id, this.testData.getAttributeAsBool("C"));//$NON-NLS-1$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsBool","D");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsBool","E");//$NON-NLS-1$ //$NON-NLS-2$
+		assertFalse(this.id, this.testData.getAttributeAsBool("F"));//$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeStringBoolean() throws Exception {
+		assertTrue(this.id, this.testData.getAttribute("A",true));//$NON-NLS-1$
+		assertTrue(this.id, this.testData.getAttribute("B",false));//$NON-NLS-1$
+		assertTrue(this.id, this.testData.getAttribute("C",false));//$NON-NLS-1$
+		assertTrue(this.id, this.testData.getAttribute("D",true));//$NON-NLS-1$
+		assertFalse(this.id, this.testData.getAttribute("E",false));//$NON-NLS-1$
+		assertFalse(this.id, this.testData.getAttribute("F",true));//$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeAsIntString() throws Exception {
+		assertEquals(this.id, 1,this.testData.getAttributeAsInt("A"));//$NON-NLS-1$
+		assertEquals(this.id, 2,this.testData.getAttributeAsInt("B"));//$NON-NLS-1$
+		assertEquals(this.id, 1, this.testData.getAttributeAsInt("C"));//$NON-NLS-1$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsInt","D");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsInt","E");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsInt","F");//$NON-NLS-1$ //$NON-NLS-2$
+	}
+	
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeStringInt() throws Exception {
+		assertEquals(this.id, 1,this.testData.getAttribute("A",5));//$NON-NLS-1$
+		assertEquals(this.id, 2,this.testData.getAttribute("B",34));//$NON-NLS-1$
+		assertEquals(this.id, 1,this.testData.getAttribute("C",18));//$NON-NLS-1$
+		assertEquals(this.id, 24,this.testData.getAttribute("D",24));//$NON-NLS-1$
+		assertEquals(this.id, -34,this.testData.getAttribute("E",-34));//$NON-NLS-1$
+		assertEquals(this.id, 18,this.testData.getAttribute("F",18));//$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeAsLongString() throws Exception {
+		assertEquals(this.id, 1,this.testData.getAttributeAsLong("A"));//$NON-NLS-1$
+		assertEquals(this.id, 2,this.testData.getAttributeAsLong("B"));//$NON-NLS-1$
+		assertEquals(this.id, 1, this.testData.getAttributeAsLong("C"));//$NON-NLS-1$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsLong","D");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsLong","E");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsLong","F");//$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributegStringLong() throws Exception {
+		assertEquals(this.id, 1,this.testData.getAttribute("A",5));//$NON-NLS-1$
+		assertEquals(this.id, 2,this.testData.getAttribute("B",34));//$NON-NLS-1$
+		assertEquals(this.id, 1,this.testData.getAttribute("C",18));//$NON-NLS-1$
+		assertEquals(this.id, 24,this.testData.getAttribute("D",24));//$NON-NLS-1$
+		assertEquals(this.id, -34,this.testData.getAttribute("E",-34));//$NON-NLS-1$
+		assertEquals(this.id, 18,this.testData.getAttribute("F",18));//$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeAsFloatString() throws Exception {
+		assertEquals(this.id, 1f,this.testData.getAttributeAsFloat("A"));//$NON-NLS-1$
+		assertEquals(this.id, 2f,this.testData.getAttributeAsFloat("B"));//$NON-NLS-1$
+		assertEquals(this.id, 1f, this.testData.getAttributeAsFloat("C"));//$NON-NLS-1$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsFloat","D");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsFloat","E");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsFloat","F");//$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeStringFloat() throws Exception {
+		assertEquals(this.id, 1f,this.testData.getAttribute("A",5f));//$NON-NLS-1$
+		assertEquals(this.id, 2f,this.testData.getAttribute("B",34f));//$NON-NLS-1$
+		assertEquals(this.id, 1f,this.testData.getAttribute("C",18f));//$NON-NLS-1$
+		assertEquals(this.id, 24f,this.testData.getAttribute("D",24f));//$NON-NLS-1$
+		assertEquals(this.id, -34f,this.testData.getAttribute("E",-34f));//$NON-NLS-1$
+		assertEquals(this.id, 18f,this.testData.getAttribute("F",18f));//$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeAsDoubleString() throws Exception {
+		assertEquals(this.id, 1.,this.testData.getAttributeAsDouble("A"));//$NON-NLS-1$
+		assertEquals(this.id, 2.,this.testData.getAttributeAsDouble("B"));//$NON-NLS-1$
+		assertEquals(this.id, 1., this.testData.getAttributeAsDouble("C"));//$NON-NLS-1$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsDouble","D");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsDouble","E");//$NON-NLS-1$ //$NON-NLS-2$
+		assertInvalidValue(this.id, this.testData,"getAttributeAsDouble","F");//$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeStringDouble() throws Exception {
+		assertEquals(this.id, 1.,this.testData.getAttribute("A",5.));//$NON-NLS-1$
+		assertEquals(this.id, 2.,this.testData.getAttribute("B",34.));//$NON-NLS-1$
+		assertEquals(this.id, 1.,this.testData.getAttribute("C",18.));//$NON-NLS-1$
+		assertEquals(this.id, 24.,this.testData.getAttribute("D",24.));//$NON-NLS-1$
+		assertEquals(this.id, -34.,this.testData.getAttribute("E",-34.));//$NON-NLS-1$
+		assertEquals(this.id, 18.,this.testData.getAttribute("F",18.));//$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeAsStringString() throws Exception {
+		assertEquals(this.id, Long.toString(1),this.testData.getAttributeAsString("A"));//$NON-NLS-1$
+		assertEquals(this.id, Double.toString(2.),this.testData.getAttributeAsString("B"));//$NON-NLS-1$
+		assertEquals(this.id, Boolean.toString(true),this.testData.getAttributeAsString("C"));//$NON-NLS-1$
+		assertEquals(this.id, "Hello",this.testData.getAttributeAsString("D"));//$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(this.id, 1.+";"+2.,this.testData.getAttributeAsString("E"));//$NON-NLS-1$ //$NON-NLS-2$		
+		assertEquals(this.id, Boolean.toString(false),this.testData.getAttributeAsString("F"));//$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAttributeStringString() throws Exception {
+		assertEquals(this.id, Long.toString(1),this.testData.getAttribute("A","default"));//$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(this.id, Double.toString(2.),this.testData.getAttribute("B","default"));//$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(this.id, Boolean.toString(true),this.testData.getAttribute("C","default"));//$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(this.id, "Hello",this.testData.getAttribute("D","default"));//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		assertEquals(this.id, 1.+";"+2.,this.testData.getAttribute("E","default"));//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		assertEquals(this.id, Boolean.toString(false),this.testData.getAttribute("F","default"));//$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	/**
+	 */
+	public void testFreeMemory() {
+		this.testData.freeMemory();
+		testIterator();
+	}
+
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractBufferedAttributeProviderTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractBufferedAttributeProviderTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/AbstractBufferedAttributeProviderTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,124 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+
+/**
+ * Stub for BufferedAttributeContrainer.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+class ReadOnlyCacheProviderStub extends AbstractBufferedAttributeProvider {
+
+	private final Attribute[] attributes;
+	
+	/**
+	 */
+	public ReadOnlyCacheProviderStub() {
+		this.attributes = new Attribute[0];
+	}
+
+	/**
+	 * @param attributes
+	 */
+	public ReadOnlyCacheProviderStub(Attribute...attributes) {
+		this.attributes = attributes;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int getAttributeCount() {
+		return this.attributes.length;
+	}
+
+	@Override
+	public Collection<String> getAllAttributeNames() {
+		ArrayList<String> list = new ArrayList<String>();
+		for (Attribute attr : this.attributes) {
+			list.add(attr.getName());
+		}
+		return list;
+	}
+
+	@Override
+	protected AttributeValue loadValue(String name) throws AttributeException {
+		for (Attribute attr : this.attributes) {
+			if (attr.getName().equals(name)) {
+				return attr;
+			}
+		}
+		throw new NoAttributeFoundException(name);
+	}
+
+	@Override
+	public void toMap(Map<String, Object> mapToFill) {
+		for(Attribute attr : this.attributes) {
+			if (attr.isAssigned()) {
+				try {
+					mapToFill.put(attr.getName(), attr.getValue());
+				}
+				catch (Exception e) {
+					throw new RuntimeException(e);
+				}
+			}
+		}
+	}
+	
+}
+
+/**
+ * Test for BufferedAttributeContainer.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class AbstractBufferedAttributeProviderTest extends AbstractAttributeProviderTest<ReadOnlyCacheProviderStub> {
+
+	/**
+	 */
+	public AbstractBufferedAttributeProviderTest() {
+		super("BufferedAttributeContainerTest"); //$NON-NLS-1$
+	}
+	
+	@Override
+	protected ReadOnlyCacheProviderStub setUpTestCase() throws Exception {
+		return new ReadOnlyCacheProviderStub(this.baseData);
+	}
+	
+}
+
+	
\ No newline at end of file

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/BufferedAttributeCollectionTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/BufferedAttributeCollectionTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/BufferedAttributeCollectionTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,165 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeException;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+
+/**
+ * Stub for CacheProvider.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+class CacheProviderStub extends BufferedAttributeCollection {
+
+	private final Map<String, Attribute> attributes = new HashMap<String,Attribute>();
+	
+	/**
+	 */
+	public CacheProviderStub() {
+		//
+	}
+
+	/**
+	 * @param attributes
+	 */
+	public CacheProviderStub(Attribute...attributes) {
+		for (Attribute attr : attributes) {
+			this.attributes.put(attr.getName(), attr);
+		}
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int getAttributeCount() {
+		return this.attributes.size();
+	}
+
+	@Override
+	public Collection<String> getAllAttributeNames() {
+		return new ArrayList<String>(this.attributes.keySet());
+	}
+
+	@Override
+	protected AttributeValue loadValue(String name) throws AttributeException {
+		Attribute attr = this.attributes.get(name);
+		if (attr!=null) return attr;
+		throw new NoAttributeFoundException(name);
+	}
+
+	@Override
+	protected boolean removeAllValues() throws AttributeException {
+		this.attributes.clear();
+		return true;
+	}
+
+	@Override
+	protected AttributeValue removeValue(String name) throws AttributeException {
+		return this.attributes.remove(name);
+	}
+
+	@Override
+	protected void saveValue(String name, AttributeValue value) throws AttributeException {
+		Attribute attr = this.attributes.get(name);
+		if (attr!=null) {
+			attr.setValue(value);
+		}
+		else {
+			this.attributes.put(name, new AttributeImpl(name,value));
+		}
+	}
+
+	@Override
+	public void setAttributes(Map<String, Object> content) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void setAttributes(AttributeProvider content)
+			throws AttributeException {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void addAttributes(Map<String, Object> content) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void addAttributes(AttributeProvider content)
+			throws AttributeException {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void toMap(Map<String, Object> mapToFill) {
+		for(Attribute attr : this.attributes.values()) {
+			if (attr.isAssigned()) {
+				try {
+					mapToFill.put(attr.getName(), attr.getValue());
+				}
+				catch (Exception e) {
+					throw new RuntimeException(e);
+				}
+			}
+		}
+	}
+
+}
+
+/**
+ * Test for BufferedAttributeProvider.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class BufferedAttributeCollectionTest extends AbstractAttributeCollectionTest<CacheProviderStub> {
+
+	/**
+	 */
+	public BufferedAttributeCollectionTest() {
+		super("BufferedAttributeProviderTest"); //$NON-NLS-1$
+	}
+	
+	@Override
+	protected CacheProviderStub setUpTestCase() throws Exception {
+		return new CacheProviderStub(this.baseData);
+	}
+	
+}
+
+	
\ No newline at end of file

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/HeapAttributeCollectionTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/HeapAttributeCollectionTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/HeapAttributeCollectionTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,49 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import org.arakhne.afc.attrs.collection.HeapAttributeCollection;
+
+
+/**
+ * Test for HeapAttributeProvider.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class HeapAttributeCollectionTest extends AbstractAttributeCollectionTest<HeapAttributeCollection> {
+
+	/**
+	 */
+	public HeapAttributeCollectionTest() {
+		super("HeapAttributeProviderTest"); //$NON-NLS-1$
+	}
+	
+	@Override
+	protected HeapAttributeCollection setUpTestCase() throws Exception {
+		return new HeapAttributeCollection();
+	}
+	
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/MultiAttributeCollectionTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/MultiAttributeCollectionTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/MultiAttributeCollectionTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,1024 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.arakhne.afc.attrs.AbstractAttrTestCase;
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.attrs.collection.AbstractAttributeProvider;
+import org.arakhne.afc.attrs.collection.HeapAttributeCollection;
+import org.arakhne.afc.attrs.collection.MultiAttributeCollection;
+
+/**
+ * Test of MultiAttributeProvider.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 4.0
+ */
+public class MultiAttributeCollectionTest extends AbstractAttrTestCase {
+
+	private MultiAttributeCollection provider;
+	private HeapAttributeCollection subprovider1;
+	private HeapAttributeCollection subprovider2;
+	private HeapAttributeCollection subprovider3;
+	private AttributeContainerStub subcontainer4;
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.provider = new MultiAttributeCollection();
+		this.subprovider1 = new HeapAttributeCollection();
+		this.subprovider2 = new HeapAttributeCollection();
+		this.subprovider3 = new HeapAttributeCollection();
+		this.subcontainer4 = new AttributeContainerStub();
+		
+		this.subprovider1.setAttribute("A", true); //$NON-NLS-1$
+		this.subprovider1.setAttribute("B", 1); //$NON-NLS-1$
+		this.subprovider1.setAttribute("C", new URL("http://www.multiagent.fr";)); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subprovider1.setAttribute("E", new URL("http://www.multiagent.fr";)); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subprovider1.setAttribute("Z1", "Z1"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		this.subprovider2.setAttribute("A", true); //$NON-NLS-1$
+		this.subprovider2.setAttribute("B", 1.); //$NON-NLS-1$
+		this.subprovider2.setAttribute("D", "abc"); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subprovider2.setAttribute("E", 1); //$NON-NLS-1$
+		this.subprovider2.setAttribute("Z2", "Z2"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		this.subprovider3.setAttribute("A", false); //$NON-NLS-1$
+		this.subprovider3.setAttribute("B", 1); //$NON-NLS-1$
+		this.subprovider3.setAttribute("C", new URL("http://www.multiagent.fr";)); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subprovider3.setAttribute("D", "abc"); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subprovider3.setAttribute("E", true); //$NON-NLS-1$
+		this.subprovider3.setAttribute("Z3", "Z3"); //$NON-NLS-1$ //$NON-NLS-2$
+		
+		this.subcontainer4.provider.setAttribute("A", true); //$NON-NLS-1$
+		this.subcontainer4.provider.setAttribute("Z4", "Z4"); //$NON-NLS-1$ //$NON-NLS-2$
+		
+		this.provider.addAttributeContainer(this.subprovider1);
+		this.provider.addAttributeContainer(this.subprovider2);
+		this.provider.addAttributeContainer(this.subprovider3);
+		this.provider.addAttributeContainer(this.subcontainer4);
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void tearDown() throws Exception {
+		this.provider = null;
+		this.subprovider1 = this.subprovider2 = this.subprovider3 = null;
+		this.subcontainer4 = null;
+		super.tearDown();
+	}
+	
+	private static Attribute makeUninitialized(String name, AttributeType type) {
+		return new AttributeImpl(name, type);
+	}
+
+	/**
+	 */
+	public void testGetAttributeContainerCount() {
+		assertEquals(4, this.provider.getAttributeContainerCount());
+	}	
+
+	/**
+	 */
+	public void testRemoveAllAttributes() {
+		assertTrue(this.provider.removeAllAttributes());
+		assertEquals(0, this.subprovider1.getAttributeCount());
+		assertEquals(0, this.subprovider2.getAttributeCount());
+		assertEquals(0, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(2, this.provider.getAttributeCount());
+
+		assertEpsilonEquals(Collections.emptyList(), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Collections.emptyList(), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Collections.emptyList(), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		assertFalse(this.provider.removeAllAttributes());
+
+		assertEpsilonEquals(Collections.emptyList(), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Collections.emptyList(), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Collections.emptyList(), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testRemoveAttributeString() throws Exception {
+		//
+		// Remove A
+		//
+		assertTrue(this.provider.removeAttribute("A")); //$NON-NLS-1$
+		assertEquals(4, this.subprovider1.getAttributeCount());
+		assertEquals(4, this.subprovider2.getAttributeCount());
+		assertEquals(5, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(9, this.provider.getAttributeCount());		
+		
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Failure on remove of ZZZ
+		//
+		assertFalse(this.provider.removeAttribute("ZZZ")); //$NON-NLS-1$
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Remove Z3
+		//
+		assertTrue(this.provider.removeAttribute("Z3")); //$NON-NLS-1$
+		assertEquals(4, this.subprovider1.getAttributeCount());
+		assertEquals(4, this.subprovider2.getAttributeCount());
+		assertEquals(4, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(8, this.provider.getAttributeCount());
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true) //$NON-NLS-1$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testRenameAttributeStringString() throws Exception {
+		//
+		// Rename A to ZZZ
+		//
+		assertTrue(this.provider.renameAttribute("A", "ZZZ")); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(5, this.subprovider1.getAttributeCount());
+		assertEquals(5, this.subprovider2.getAttributeCount());
+		assertEquals(6, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", false), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Rename TOTOZZZ to A
+		//
+		assertFalse(this.provider.renameAttribute("TOTOZZZ", "A")); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(5, this.subprovider1.getAttributeCount());
+		assertEquals(5, this.subprovider2.getAttributeCount());
+		assertEquals(6, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", false), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Rename Z4 to C
+		//
+		assertFalse(this.provider.renameAttribute("TOTOZZZ", "A")); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(5, this.subprovider1.getAttributeCount());
+		assertEquals(5, this.subprovider2.getAttributeCount());
+		assertEquals(6, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", false), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testRenameAttributeStringStringBoolean() throws Exception {
+		//
+		// Rename A to ZZZ
+		//
+		assertTrue(this.provider.renameAttribute("A", "ZZZ")); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(5, this.subprovider1.getAttributeCount());
+		assertEquals(5, this.subprovider2.getAttributeCount());
+		assertEquals(6, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", false), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Rename TOTOZZZ to A
+		//
+		assertFalse(this.provider.renameAttribute("TOTOZZZ", "A")); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(5, this.subprovider1.getAttributeCount());
+		assertEquals(5, this.subprovider2.getAttributeCount());
+		assertEquals(6, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", false), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Rename Z4 to C
+		//
+		assertFalse(this.provider.renameAttribute("TOTOZZZ", "A")); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(5, this.subprovider1.getAttributeCount());
+		assertEquals(5, this.subprovider2.getAttributeCount());
+		assertEquals(6, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", false), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeStringAttributeValue() throws Exception {
+		//
+		// Set ZZZ
+		//
+		assertEquals(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				this.provider.setAttribute("ZZZ", new AttributeValueImpl("xyz"))); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(6, this.subprovider1.getAttributeCount());
+		assertEquals(6, this.subprovider2.getAttributeCount());
+		assertEquals(7, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", false), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Set B
+		//
+		assertEquals(
+				new AttributeImpl("B", "def"), //$NON-NLS-1$ //$NON-NLS-2$
+				this.provider.setAttribute("B", new AttributeValueImpl("def"))); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(6, this.subprovider1.getAttributeCount());
+		assertEquals(6, this.subprovider2.getAttributeCount());
+		assertEquals(7, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("B", "def"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("B", "def"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", false), //$NON-NLS-1$
+				new AttributeImpl("B", "def"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeAttribute() throws Exception {
+		//
+		// Set ZZZ
+		//
+		assertEquals(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				this.provider.setAttribute(new AttributeImpl("ZZZ", "xyz"))); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(6, this.subprovider1.getAttributeCount());
+		assertEquals(6, this.subprovider2.getAttributeCount());
+		assertEquals(7, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", false), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Set B
+		//
+		assertEquals(
+				new AttributeImpl("B", "def"), //$NON-NLS-1$ //$NON-NLS-2$
+				this.provider.setAttribute(new AttributeImpl("B", "def"))); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals(6, this.subprovider1.getAttributeCount());
+		assertEquals(6, this.subprovider2.getAttributeCount());
+		assertEquals(7, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(10, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("B", "def"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("B", "def"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("ZZZ", "xyz"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("A", false), //$NON-NLS-1$
+				new AttributeImpl("B", "def"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("ZZZ", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testSetAttributeTypeStringAttributeType() throws Exception {
+		//
+		// Set type of A to STRING
+		//
+		assertEquals(
+				makeUninitialized("A", AttributeType.STRING), //$NON-NLS-1$
+				this.provider.setAttributeType("A", AttributeType.STRING)); //$NON-NLS-1$
+
+		assertEquals(5, this.subprovider1.getAttributeCount());
+		assertEquals(5, this.subprovider2.getAttributeCount());
+		assertEquals(6, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(9, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", Boolean.TRUE.toString()), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", Boolean.TRUE.toString()), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", Boolean.FALSE.toString()), //$NON-NLS-1$
+				new AttributeImpl("B", 1.), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.INTEGER), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+
+		//
+		// Set type of B to STRING
+		//
+		assertEquals(
+				makeUninitialized("B", AttributeType.STRING), //$NON-NLS-1$
+				this.provider.setAttributeType("B", AttributeType.STRING)); //$NON-NLS-1$
+
+		assertEquals(5, this.subprovider1.getAttributeCount());
+		assertEquals(5, this.subprovider2.getAttributeCount());
+		assertEquals(6, this.subprovider3.getAttributeCount());
+		assertEquals(2, this.subcontainer4.getAttributeCount());
+		assertEquals(9, this.provider.getAttributeCount());		
+
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", Boolean.TRUE.toString()), //$NON-NLS-1$
+				new AttributeImpl("B", Long.toString(1)), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("Z1", "Z1") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider1.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", Boolean.TRUE.toString()), //$NON-NLS-1$
+				new AttributeImpl("B", Double.toString(1.)), //$NON-NLS-1$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", 1), //$NON-NLS-1$
+				new AttributeImpl("Z2", "Z2") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider2.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", Boolean.FALSE.toString()), //$NON-NLS-1$
+				new AttributeImpl("B", Long.toString(1)), //$NON-NLS-1$
+				new AttributeImpl("C", new URL("http://www.multiagent.fr";)), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("D", "abc"), //$NON-NLS-1$ //$NON-NLS-2$
+				new AttributeImpl("E", true), //$NON-NLS-1$
+				new AttributeImpl("Z3", "Z3") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subprovider3.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("A", true), //$NON-NLS-1$
+				new AttributeImpl("Z4", "Z4") //$NON-NLS-1$ //$NON-NLS-2$
+		), this.subcontainer4.getAllAttributes());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("B", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z4", AttributeType.STRING) //$NON-NLS-1$
+		), this.provider.getAllAttributes());
+	}
+
+	/**
+	 * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 * @since 4.0
+	 */
+	private static class AttributeContainerStub extends AbstractAttributeProvider {
+
+		/** Attribute provider wrapped by this stub.
+		 */
+		public final HeapAttributeCollection provider = new HeapAttributeCollection();
+		
+		/**
+		 */
+		public AttributeContainerStub() {
+			//
+		}
+		
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public void freeMemory() {
+			this.provider.freeMemory();
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public Collection<String> getAllAttributeNames() {
+			return this.provider.getAllAttributeNames();
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public Collection<Attribute> getAllAttributes() {
+			return this.provider.getAllAttributes();
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public Map<AttributeType, Collection<Attribute>> getAllAttributesByType() {
+			return this.provider.getAllAttributesByType();
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public AttributeValue getAttribute(String name) {
+			return this.provider.getAttribute(name);
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public AttributeValue getAttribute(String name, AttributeValue defaultValue) {
+			return this.provider.getAttribute(name, defaultValue);
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public int getAttributeCount() {
+			return this.provider.getAttributeCount();
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public Attribute getAttributeObject(String name) {
+			return this.provider.getAttributeObject(name);
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public boolean hasAttribute(String name) {
+			return this.provider.hasAttribute(name);
+		}
+
+		@Override
+		public void toMap(Map<String, Object> mapToFill) {
+			this.provider.toMap(mapToFill);
+		}
+		
+	}
+	
+}

Added: trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/MultiAttributeProviderTest.java
===================================================================
--- trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/MultiAttributeProviderTest.java	                        (rev 0)
+++ trunk/attrs/src/test/java/org/arakhne/afc/attrs/collection/MultiAttributeProviderTest.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,325 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
+ *                        Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.attrs.collection;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+
+import org.arakhne.afc.attrs.AbstractAttrTestCase;
+import org.arakhne.afc.attrs.attr.Attribute;
+import org.arakhne.afc.attrs.attr.AttributeImpl;
+import org.arakhne.afc.attrs.attr.AttributeType;
+import org.arakhne.afc.attrs.attr.AttributeValue;
+import org.arakhne.afc.attrs.attr.AttributeValueImpl;
+import org.arakhne.afc.attrs.collection.HeapAttributeCollection;
+import org.arakhne.afc.attrs.collection.MultiAttributeProvider;
+
+/**
+ * Test of MultiAttributeContainer.
+ * 
+ * @author St&eacute;phane GALLAND &lt;stephane.galland@xxxxxxx&gt;
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 4.0
+ */
+public class MultiAttributeProviderTest extends AbstractAttrTestCase {
+
+	private MultiAttributeProvider container;
+	private HeapAttributeCollection subcontainer1;
+	private HeapAttributeCollection subcontainer2;
+	private HeapAttributeCollection subcontainer3;
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.container = new MultiAttributeProvider();
+		this.subcontainer1 = new HeapAttributeCollection();
+		this.subcontainer2 = new HeapAttributeCollection();
+		this.subcontainer3 = new HeapAttributeCollection();
+		
+		this.subcontainer1.setAttribute("A", true); //$NON-NLS-1$
+		this.subcontainer1.setAttribute("B", 1); //$NON-NLS-1$
+		this.subcontainer1.setAttribute("C", new URL("http://www.multiagent.fr";)); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subcontainer1.setAttribute("E", new URL("http://www.multiagent.fr";)); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subcontainer1.setAttribute("Z1", "Z1"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		this.subcontainer2.setAttribute("A", true); //$NON-NLS-1$
+		this.subcontainer2.setAttribute("B", 1.); //$NON-NLS-1$
+		this.subcontainer2.setAttribute("D", "abc"); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subcontainer2.setAttribute("E", 1); //$NON-NLS-1$
+		this.subcontainer2.setAttribute("Z2", "Z2"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		this.subcontainer3.setAttribute("A", false); //$NON-NLS-1$
+		this.subcontainer3.setAttribute("B", 1); //$NON-NLS-1$
+		this.subcontainer3.setAttribute("C", new URL("http://www.multiagent.fr";)); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subcontainer3.setAttribute("D", "abc"); //$NON-NLS-1$ //$NON-NLS-2$
+		this.subcontainer3.setAttribute("E", true); //$NON-NLS-1$
+		this.subcontainer3.setAttribute("Z3", "Z3"); //$NON-NLS-1$ //$NON-NLS-2$
+		
+		this.container.addAttributeContainer(this.subcontainer1);
+		this.container.addAttributeContainer(this.subcontainer2);
+		this.container.addAttributeContainer(this.subcontainer3);
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void tearDown() throws Exception {
+		this.container = null;
+		this.subcontainer1 = this.subcontainer2 = this.subcontainer3 = null;
+		super.tearDown();
+	}
+	
+	/**
+	 */
+	public void testGetAttributeCount() {
+		assertEquals(8, this.container.getAttributeCount());
+	}
+	
+	/**
+	 */
+	public void testGetAttributeContainerCount() {
+		assertEquals(3, this.container.getAttributeContainerCount());
+	}	
+
+	/**
+	 */
+	public void testGetAllAttributeNames() {
+		Collection<String> names = this.container.getAllAttributeNames();
+		assertNotNull(names);
+		assertEquals(8, names.size());
+		assertEpsilonEquals(Arrays.asList(
+				"A", //$NON-NLS-1$
+				"B", //$NON-NLS-1$
+				"C", //$NON-NLS-1$
+				"D", //$NON-NLS-1$
+				"E", //$NON-NLS-1$
+				"Z1", //$NON-NLS-1$
+				"Z2", //$NON-NLS-1$
+				"Z3" //$NON-NLS-1$
+				), names);
+	}
+	
+	private static void assertUninitialized(AttributeType type, AttributeValue v) {
+		assertNotNull(v);
+		assertEquals(type, v.getType());
+		assertFalse(v.isAssigned());
+	}
+
+	private static Attribute makeUninitialized(String name, AttributeType type) {
+		return new AttributeImpl(name, type);
+	}
+
+	/**
+	 */
+	public void testHasAttributeString() {
+		assertTrue(this.container.hasAttribute("A")); //$NON-NLS-1$
+		assertTrue(this.container.hasAttribute("B")); //$NON-NLS-1$
+		assertTrue(this.container.hasAttribute("C")); //$NON-NLS-1$
+		assertTrue(this.container.hasAttribute("D")); //$NON-NLS-1$
+		assertTrue(this.container.hasAttribute("E")); //$NON-NLS-1$
+		assertFalse(this.container.hasAttribute("F")); //$NON-NLS-1$
+		assertTrue(this.container.hasAttribute("Z1")); //$NON-NLS-1$
+		assertTrue(this.container.hasAttribute("Z2")); //$NON-NLS-1$
+		assertTrue(this.container.hasAttribute("Z3")); //$NON-NLS-1$
+		assertFalse(this.container.hasAttribute("Z4")); //$NON-NLS-1$
+	}
+
+	/**
+	 */
+	public void testGetAttributeString() {
+		assertUninitialized(AttributeType.BOOLEAN,
+				this.container.getAttribute("A")); //$NON-NLS-1$
+		assertEquals(new AttributeValueImpl(1),
+				this.container.getAttribute("B")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.URL,
+				this.container.getAttribute("C")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttribute("D")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.OBJECT,
+				this.container.getAttribute("E")); //$NON-NLS-1$
+		assertNull(this.container.getAttribute("F")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttribute("Z1")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttribute("Z2")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttribute("Z3")); //$NON-NLS-1$
+		assertNull(this.container.getAttribute("Z4")); //$NON-NLS-1$
+	}
+
+	/**
+	 */
+	public void testGetAttributeStringAttributeValue() {
+		AttributeValue defaultValue = new AttributeValueImpl(456);
+		assertUninitialized(AttributeType.BOOLEAN,
+				this.container.getAttribute("A", defaultValue)); //$NON-NLS-1$
+		assertEquals(new AttributeValueImpl(1),
+				this.container.getAttribute("B", defaultValue)); //$NON-NLS-1$
+		assertUninitialized(AttributeType.URL,
+				this.container.getAttribute("C", defaultValue)); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttribute("D", defaultValue)); //$NON-NLS-1$
+		assertUninitialized(AttributeType.OBJECT,
+				this.container.getAttribute("E", defaultValue)); //$NON-NLS-1$
+		assertSame(defaultValue, this.container.getAttribute("F", defaultValue)); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttribute("Z1", defaultValue)); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttribute("Z2", defaultValue)); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttribute("Z3", defaultValue)); //$NON-NLS-1$
+		assertSame(defaultValue, this.container.getAttribute("Z4", defaultValue)); //$NON-NLS-1$
+	}
+
+	/**
+	 */
+	public void testGetAttributeObjectString() {
+		assertUninitialized(AttributeType.BOOLEAN,
+				this.container.getAttributeObject("A")); //$NON-NLS-1$
+		assertEquals(new AttributeImpl("B",1), //$NON-NLS-1$
+				this.container.getAttributeObject("B")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.URL,
+				this.container.getAttributeObject("C")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttributeObject("D")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.OBJECT,
+				this.container.getAttributeObject("E")); //$NON-NLS-1$
+		assertNull(this.container.getAttribute("F")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttributeObject("Z1")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttributeObject("Z2")); //$NON-NLS-1$
+		assertUninitialized(AttributeType.STRING,
+				this.container.getAttributeObject("Z3")); //$NON-NLS-1$
+		assertNull(this.container.getAttributeObject("Z4")); //$NON-NLS-1$
+	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testGetAllAttributes() throws Exception {
+		Collection<Attribute> attrs = this.container.getAllAttributes();
+		assertNotNull(attrs);
+		assertEquals(8, attrs.size());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.BOOLEAN), //$NON-NLS-1$
+				new AttributeImpl("B", 1), //$NON-NLS-1$
+				makeUninitialized("C", AttributeType.URL), //$NON-NLS-1$
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("E", AttributeType.OBJECT), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING) //$NON-NLS-1$
+		), attrs);
+	}
+
+	/**
+	 */
+	public void testGetAllAttributesByType() {
+		Map<AttributeType,Collection<Attribute>> attrsbytype = this.container.getAllAttributesByType();
+		assertNotNull(attrsbytype);
+		assertEquals(5, attrsbytype.size());
+		
+		Collection<Attribute> attrs;
+		
+		attrs = attrsbytype.get(AttributeType.BOOLEAN);
+		assertNotNull(attrs);
+		assertEquals(1, attrs.size());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("A", AttributeType.BOOLEAN) //$NON-NLS-1$
+		), attrs);
+		
+		attrs = attrsbytype.get(AttributeType.COLOR);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.DATE);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.IMAGE);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.INTEGER);
+		assertNotNull(attrs);
+		assertEquals(1, attrs.size());
+		assertEpsilonEquals(Arrays.asList(
+				new AttributeImpl("B", 1) //$NON-NLS-1$
+		), attrs);
+
+		attrs = attrsbytype.get(AttributeType.OBJECT);
+		assertNotNull(attrs);
+		assertEquals(1, attrs.size());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("E", AttributeType.OBJECT) //$NON-NLS-1$
+		), attrs);
+
+		attrs = attrsbytype.get(AttributeType.POINT);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.POINT3D);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.POLYLINE);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.POLYLINE3D);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.REAL);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.STRING);
+		assertNotNull(attrs);
+		assertEquals(4, attrs.size());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("D", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z1", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z2", AttributeType.STRING), //$NON-NLS-1$
+				makeUninitialized("Z3", AttributeType.STRING) //$NON-NLS-1$
+		), attrs);
+
+		attrs = attrsbytype.get(AttributeType.TIMESTAMP);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.URI);
+		assertNull(attrs);
+
+		attrs = attrsbytype.get(AttributeType.URL);
+		assertNotNull(attrs);
+		assertEquals(1, attrs.size());
+		assertEpsilonEquals(Arrays.asList(
+				makeUninitialized("C", AttributeType.URL) //$NON-NLS-1$
+		), attrs);
+
+		attrs = attrsbytype.get(AttributeType.UUID);
+		assertNull(attrs);
+	}
+
+}


Property changes on: trunk/math
___________________________________________________________________
Added: svn:ignore
   + .classpath
..metadata
..settings
..project
target
bin


Added: trunk/math/pom.xml
===================================================================
--- trunk/math/pom.xml	                        (rev 0)
+++ trunk/math/pom.xml	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,26 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+		<artifactId>afc</artifactId>
+		<groupId>org.arakhne.afc</groupId>
+		<version>4.5-SNAPSHOT</version>
+  </parent>
+  
+  <groupId>org.arakhne.afc</groupId>
+  <artifactId>math</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <name>Arakhne Math Tools</name>
+  
+  <dependencies>
+  	<dependency>
+  		<groupId>org.arakhne.afc</groupId>
+  		<artifactId>arakhneVmutils</artifactId>
+  	</dependency>
+  	<dependency>
+  		<groupId>junit</groupId>
+  		<artifactId>junit</artifactId>
+  		<scope>test</scope>
+  	</dependency>
+  </dependencies>
+  
+</project>

Added: trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_circle.png
===================================================================
(Binary files differ)


Property changes on: trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_circle.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_point.png
===================================================================
(Binary files differ)


Property changes on: trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_point.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_rect.png
===================================================================
(Binary files differ)


Property changes on: trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_rect.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_segment.png
===================================================================
(Binary files differ)


Property changes on: trunk/math/src/javadoc/org/arakhne/math/discrete/object2d/doc-files/crossing_segment.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/math/src/javadoc/org/arakhne/math/generic/doc-files/fillrule-evenodd.png
===================================================================
(Binary files differ)


Property changes on: trunk/math/src/javadoc/org/arakhne/math/generic/doc-files/fillrule-evenodd.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/math/src/javadoc/org/arakhne/math/generic/doc-files/fillrule-nonzero.png
===================================================================
(Binary files differ)


Property changes on: trunk/math/src/javadoc/org/arakhne/math/generic/doc-files/fillrule-nonzero.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/math/src/main/java/org/arakhne/afc/math/MathConstants.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/MathConstants.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/MathConstants.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,145 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (c) 2006-10, Multiagent Team, Laboratoire Systemes et Transports, Universite de Technologie de Belfort-Montbeliard.
+ * Copyright (C) 2012 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math;
+
+/** Several mathematical constants.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface MathConstants {
+
+	/** Inside zone according to the Cohen-Sutherland algorithm.
+	 */
+	public static final int COHEN_SUTHERLAND_INSIDE = 0; // 0000
+	/** Left zone according to the Cohen-Sutherland algorithm.
+	 */
+	public static final int COHEN_SUTHERLAND_LEFT = 1;   // 0001
+	/** Right zone according to the Cohen-Sutherland algorithm.
+	 */
+	public static final int COHEN_SUTHERLAND_RIGHT = 2;  // 0010
+	/** Bottom zone according to the Cohen-Sutherland algorithm.
+	 */
+	public static final int COHEN_SUTHERLAND_BOTTOM = 4; // 0100
+	/** Top zone according to the Cohen-Sutherland algorithm.
+	 */
+	public static final int COHEN_SUTHERLAND_TOP = 8;    // 1000
+	
+	/** PI
+	 */
+	public static final float PI = (float)Math.PI;
+
+	/** E
+	 */
+	public static final float E = (float)Math.E;
+
+	/** Epsilon value, smallest such that 1.0+EPSILON != 1.0
+	 * <p>
+	 * Given by the Java3D's implementation of the Matrix3d class.
+	 */
+	public static final double EPSILON = 1.110223024E-16;
+
+	/** 2 * PI
+	 */
+	public static final float TWO_PI = 2f * PI;
+
+	/** PI + PI/2
+	 */
+	public static final float ONE_HALF_PI = 1.5f * PI;
+
+	/** PI/2
+	 */
+	public static final float DEMI_PI = .5f * PI;
+
+	/** PI/4
+	 */
+	public static final float QUARTER_PI = .25f * PI;
+
+	/** 3*PI/4
+	 */
+	public static final float THREE_QUARTER_PI = .75f * PI;
+
+	/** Square root of 2
+	 */
+	public static final float SQRT_2 = (float)Math.sqrt(2.);
+
+	/**
+	 * Max sweeps in the Jacoby's algorithms.
+	 */
+	public static final int JACOBI_MAX_SWEEPS = 32;
+	
+	/**
+	 * Max sweeps in the Ellipse's algorithms.
+	 */
+	public static final int ELLIPSE_MAX_SWEEPS = 32;
+
+	/** This is the maximale distance that
+	 *  permits to detect hits.
+	 */
+	public static final float HIT_DISTANCE = 5f ;
+
+	/** The maximum distance that the line 
+	 *  segments used to approximate the 
+	 *  curved segments are allowed to 
+	 *  deviate from any point on the 
+	 *  original curve.
+	 *  <p>
+	 *  This attributes is used to parameter the approximation
+	 *  of the curve rendering.
+	 */
+	public static final float SPLINE_APPROXIMATION_RATIO = .1f;
+	
+	/**
+     * The rectangle intersection test counts the number of times
+     * that the path crosses through the shadow that the rectangle
+     * projects to the right towards (x => +INFINITY).
+     *
+     * During processing of the path it actually counts every time
+     * the path crosses either or both of the top and bottom edges
+     * of that shadow.  If the path enters from the top, the count
+     * is incremented.  If it then exits back through the top, the
+     * same way it came in, the count is decremented and there is
+     * no impact on the winding count.  If, instead, the path exits
+     * out the bottom, then the count is incremented again and a
+     * full pass through the shadow is indicated by the winding count
+     * having been incremented by 2.
+     *
+     * Thus, the winding count that it accumulates is actually double
+     * the real winding count.  Since the path is continuous, the
+     * final answer should be a multiple of 2, otherwise there is a
+     * logic error somewhere.
+     *
+     * If the path ever has a direct hit on the rectangle, then a
+     * special value is returned.  This special value terminates
+     * all ongoing accumulation on up through the call chain and
+     * ends up getting returned to the calling function which can
+     * then produce an answer directly.  For intersection tests,
+     * the answer is always "true" if the path intersects the
+     * rectangle.  For containment tests, the answer is always
+     * "false" if the path intersects the rectangle.  Thus, no
+     * further processing is ever needed if an intersection occurs.
+     */
+    public static final int SHAPE_INTERSECTS = 0x80000000;
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/MathUtil.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/MathUtil.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/MathUtil.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,1678 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2011 Janus Core Developers
+ * Copyright (C) 2012 Stéphane GALLAND
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.arakhne.afc.math;
+
+import org.arakhne.afc.math.continous.object2d.Point2f;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Vector2D;
+
+/** Mathematic and geometric utilities.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class MathUtil implements MathConstants {
+
+	/** Clamp the given angle in radians to {@code [0;2PI)}.
+	 * 
+	 * @param radians is the angle to clamp
+	 * @return the angle in {@code [0;2PI)} range.
+	 */
+	public static float clampRadian(float radians) {
+		float r = radians;
+		while (r<0f) r += TWO_PI;
+		while (r>=TWO_PI) r -= TWO_PI;
+		return r;
+	}
+
+	/** Clamp the given value to the given range.
+	 * <p>
+	 * If the value is outside the {@code [min;max]}
+	 * range, it is clamp to the nearest bounding value
+	 * <var>min</var> or <var>max</var>.
+	 * 
+	 * @param v is the value to clamp.
+	 * @param min is the min value of the range.
+	 * @param max is the max value of the range.
+	 * @return the value in {@code [min;max]} range.
+	 */
+	public static float clamp(float v, float min, float max) {
+		if (min<max) {
+			if (v<min) return min;
+			if (v>max) return max;
+		}
+		else {
+			if (v>min) return min;
+			if (v<max) return max;
+		}
+		return v;
+	}	
+
+	/** Replies if the given value is near zero.
+	 * 
+	 * @param value is the value to test.
+	 * @return <code>true</code> if the given <var>value</var>
+	 * is near zero, otherwise <code>false</code>.
+	 */
+	public static boolean isEpsilonZero(float value) {
+		return Math.abs(value) <= EPSILON;
+	}
+
+	/** Replies if the given values are near.
+	 * 
+	 * @param v1
+	 * @param v2
+	 * @return <code>true</code> if the given <var>v1</var>
+	 * is near <var>v2</var>, otherwise <code>false</code>.
+	 */
+	public static boolean isEpsilonEqual(float v1, float v2) {
+		return Math.abs(v1 - v2) <= EPSILON;
+	}
+
+	/** Replies the max value.
+	 * 
+	 * @param values are the values to scan.
+	 * @return the max value.
+	 */
+	public static float max(float... values) {
+		if (values==null || values.length==0) return Float.NaN;
+		float m = values[0];
+		for(float v : values) {
+			if (v>m) m = v;
+		}
+		return m;
+	}
+
+	/** Replies the max value.
+	 * 
+	 * @param values are the values to scan.
+	 * @return the max value.
+	 */
+	public static int max(int... values) {
+		if (values==null || values.length==0) return 0;
+		int m = values[0];
+		for(int v : values) {
+			if (v>m) m = v;
+		}
+		return m;
+	}
+
+	/** Replies the min value.
+	 * 
+	 * @param values are the values to scan.
+	 * @return the min value.
+	 */
+	public static float min(float... values) {
+		if (values==null || values.length==0) return Float.NaN;
+		float m = values[0];
+		for(float v : values) {
+			if (v<m) m = v;
+		}
+		return m;
+	}
+
+	/** Replies the min value.
+	 * 
+	 * @param values are the values to scan.
+	 * @return the min value.
+	 */
+	public static int min(int... values) {
+		if (values==null || values.length==0) return 0;
+		int m = values[0];
+		for(int v : values) {
+			if (v<m) m = v;
+		}
+		return m;
+	}
+
+	/** Compute the distance between a point and a segment.
+	 *
+	 * @param px horizontal position of the point.
+	 * @param py vertical position of the point.
+	 * @param x1 horizontal position of the first point of the segment.
+	 * @param y1 vertical position of the first point of the segment.
+	 * @param x2 horizontal position of the second point of the segment.
+	 * @param y2 vertical position of the second point of the segment.
+	 * @return the distance beetween the point and the segment.
+	 */
+	public static final float distancePointToSegment(float px, float py, float x1, float y1, float x2, float y2) {
+		return distancePointToSegment(px, py, x1, y1, x2, y2, null);
+	}
+
+	/** Compute the square distance between a point and a segment.
+	 *
+	 * @param px horizontal position of the point.
+	 * @param py vertical position of the point.
+	 * @param x1 horizontal position of the first point of the segment.
+	 * @param y1 vertical position of the first point of the segment.
+	 * @param x2 horizontal position of the second point of the segment.
+	 * @param y2 vertical position of the second point of the segment.
+	 * @return the distance beetween the point and the segment.
+	 */
+	public static final float distanceSquaredPointToSegment(float px, float py, float x1, float y1, float x2, float y2) {
+		return distanceSquaredPointToSegment(px, py, x1, y1, x2, y2, null);
+	}
+
+	/** Compute the distance between a point and a segment.
+	 *
+	 * @param px horizontal position of the point.
+	 * @param py vertical position of the point.
+	 * @param x1 horizontal position of the first point of the segment.
+	 * @param y1 vertical position of the first point of the segment.
+	 * @param x2 horizontal position of the second point of the segment.
+	 * @param y2 vertical position of the second point of the segment.
+	 * @param pts is the point that will be set with the coordinates of the nearest point,
+	 * if not <code>null</code>.
+	 * @return the distance beetween the point and the segment.
+	 */
+	public static final float distancePointToSegment(float px, float py, float x1, float y1, float x2, float y2, Point2D pts) {
+		float r_denomenator = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
+		if (r_denomenator==0.) return distancePointToPoint(px, py, x1, y1);
+		float r_numerator = (px-x1)*(x2-x1) + (py-y1)*(y2-y1);
+		float ratio = r_numerator / r_denomenator;
+
+		if (ratio<=0.) {
+			if (pts!=null) pts.set(x1, y1);
+			return (float)Math.sqrt((px-x1)*(px-x1) + (py-y1)*(py-y1));
+		}
+
+		if (ratio>=1.) {
+			if (pts!=null) pts.set(x2, y2);
+			return (float)Math.sqrt((px-x2)*(px-x2) + (py-y2)*(py-y2));
+		}
+
+		if (pts!=null) pts.set(
+				ratio * (x2-x1),
+				ratio * (y2-y1));
+
+		float s =  ((y1-py)*(x2-x1)-(x1-px)*(y2-y1) ) / r_denomenator;
+		return (float)(Math.abs(s) * Math.sqrt(r_denomenator));
+	}
+
+	/** Compute the square distance between a point and a segment.
+	 *
+	 * @param px horizontal position of the point.
+	 * @param py vertical position of the point.
+	 * @param x1 horizontal position of the first point of the segment.
+	 * @param y1 vertical position of the first point of the segment.
+	 * @param x2 horizontal position of the second point of the segment.
+	 * @param y2 vertical position of the second point of the segment.
+	 * @param pts is the point that will be set with the coordinates of the nearest point,
+	 * if not <code>null</code>.
+	 * @return the distance beetween the point and the segment.
+	 */
+	public static final float distanceSquaredPointToSegment(float px, float py, float x1, float y1, float x2, float y2, Point2D pts) {
+		float r_denomenator = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
+		if (r_denomenator==0f) return distanceSquaredPointToPoint(px, py, x1, y1);
+		float r_numerator = (px-x1)*(x2-x1) + (py-y1)*(y2-y1);
+		float ratio = r_numerator / r_denomenator;
+
+		if (ratio<=0f) {
+			if (pts!=null) pts.set(x1, y1);
+			return Math.abs((px-x1)*(px-x1) + (py-y1)*(py-y1));
+		}
+
+		if (ratio>=1f) {
+			if (pts!=null) pts.set(x2, y2);
+			return Math.abs((px-x2)*(px-x2) + (py-y2)*(py-y2));
+		}
+
+		if (pts!=null) pts.set(
+				ratio * (x2-x1),
+				ratio * (y2-y1));
+
+		float s =  ((y1-py)*(x2-x1)-(x1-px)*(y2-y1) ) / r_denomenator;
+		return (s * s) * Math.abs(r_denomenator);
+	}
+
+	/** Compute the distance between a point and a line.
+	 *
+	 * @param px horizontal position of the point.
+	 * @param py vertical position of the point.
+	 * @param x1 horizontal position of the first point of the line.
+	 * @param y1 vertical position of the first point of the line.
+	 * @param x2 horizontal position of the second point of the line.
+	 * @param y2 vertical position of the second point of the line.
+	 * @return the distance beetween the point and the line.
+	 * @see #distanceSquaredPointToLine(float, float, float, float, float, float)
+	 * @see #relativeDistancePointToLine(float, float, float, float, float, float)
+	 */
+	public static final float distancePointToLine(float px, float py, float x1, float y1, float x2, float y2) {
+		float r_denomenator = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
+		if (r_denomenator==0.) return distancePointToPoint(px, py, x1, y1);
+		float s = ((y1-py)*(x2-x1)-(x1-px)*(y2-y1) ) / r_denomenator;
+		return (float)(Math.abs(s) * Math.sqrt(r_denomenator));
+	}
+
+	/** Compute the distance between a point and a line.
+	 *
+	 * @param px horizontal position of the point.
+	 * @param py vertical position of the point.
+	 * @param x1 horizontal position of the first point of the line.
+	 * @param y1 vertical position of the first point of the line.
+	 * @param x2 horizontal position of the second point of the line.
+	 * @param y2 vertical position of the second point of the line.
+	 * @return the distance beetween the point and the line.
+	 * @see #distancePointToLine(float, float, float, float, float, float)
+	 */
+	public static final float distanceSquaredPointToLine(float px, float py, float x1, float y1, float x2, float y2) {
+		float r_denomenator = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
+		if (r_denomenator==0.) return distanceSquaredPointToPoint(px, py, x1, y1);
+		float s = ((y1-py)*(x2-x1)-(x1-px)*(y2-y1) ) / r_denomenator;
+		return (s * s) * Math.abs(r_denomenator);
+	}
+
+	/** Compute the distance between 2 points.
+	 *
+	 * @param x1 horizontal position of the first point.
+	 * @param y1 vertical position of the first point.
+	 * @param x2 horizontal position of the second point.
+	 * @param y2 vertical position of the second point.
+	 * @return the distance between given points.
+	 * @see #distanceSquaredPointToPoint(float, float, float, float)
+	 */
+	public static final float distancePointToPoint(float x1, float y1, float x2, float y2) {
+		float dx, dy;
+		dx = x1 - x2;
+		dy = y1 - y2;
+		return (float)Math.sqrt(dx*dx+dy*dy);
+	}
+
+	/** Compute the squared distance between 2 points.
+	 *
+	 * @param x1 horizontal position of the first point.
+	 * @param y1 vertical position of the first point.
+	 * @param x2 horizontal position of the second point.
+	 * @param y2 vertical position of the second point.
+	 * @return the squared distance between given points.
+	 * @see #distancePointToPoint(float, float, float, float)
+	 */
+	public static final float distanceSquaredPointToPoint(float x1, float y1, float x2, float y2) {
+		float dx, dy;
+		dx = x1 - x2;
+		dy = y1 - y2;
+		return dx*dx+dy*dy;
+	}
+
+	/**
+	 * Replies the specified angle translated between 0 and 2PI.
+	 * 
+	 * @param radian
+	 *            is an angle
+	 * @return normalized angle
+	 */
+	public static float clampRadian0To2PI(float radian) {
+		if ((!Float.isNaN(radian)) && (!Float.isInfinite(radian))) {
+			return clampTrigo(radian, 0, 2f*PI);
+		}
+		return radian;
+	}
+
+	/**
+	 * Replies the specified angle translated between -PI and PI.
+	 * 
+	 * @param radian
+	 *            is an angle
+	 * @return normalized angle
+	 */
+	public static float clampRadianMinusPIToPI(float radian) {
+		if ((!Float.isNaN(radian)) && (!Float.isInfinite(radian))) {
+			return clampTrigo(radian, -PI, PI);
+		}
+		return radian;
+	}
+
+	/**
+	 * Replies the specified angle translated between 0 and 360.
+	 * 
+	 * @param degree
+	 *            is an angle
+	 * @return normalized angle
+	 */
+	public static float clampDegree0To360(float degree) {
+		if ((!Float.isNaN(degree)) && (!Float.isInfinite(degree))) {
+			return clampTrigo(degree, 0, 360);
+		}
+		return degree;
+	}
+
+	/**
+	 * Replies the specified angle translated between -180 and 180.
+	 * 
+	 * @param degree
+	 *            is an angle
+	 * @return normalized angle
+	 */
+	public static float clampDegreeMinus180To180(float degree) {
+		if ((!Float.isNaN(degree)) && (!Float.isInfinite(degree))) {
+			return clampTrigo(degree, -180, 180);
+		}
+		return degree;
+	}
+
+	/** Clamp the given value to fit between the min and max values
+	 * according to a trigonometric-like heuristic.
+	 * If the given value is not between the minimum and maximum
+	 * values and the value is positive, the value is modulo the perimeter
+	 * of the counterclockwise circle.
+	 * If the given value is not between the minimum and maximum
+	 * values and the value is negative, the value is modulo the perimeter
+	 * of the clockwise circle.
+	 * The perimeter is the distance between <var>min</var> and <var>max</var>.
+	 * 
+	 * @param value
+	 * @param min
+	 * @param max
+	 * @return the clamped value
+	 */
+	public static float clampTrigo(float value, float min, float max) {
+		if (Float.isNaN(max)) { // NaN is lower than all the number according to float.compareTo()
+			return Float.NaN;
+		}
+		if (Float.isNaN(min)) {
+			// Clamp max only
+			if (value>max) return max - Float.MAX_VALUE + value;
+		}
+		else {
+			assert(min<=max);
+			if (min==max) return min; // special case: empty interval
+			if (value<min || value >max) {
+				float perimeter = max - min;
+				float nvalue = value - min;
+				float rest = nvalue % perimeter;
+				return (value<0) ? max+rest : rest+min;
+			}
+		}
+		return value;
+	}
+
+	/**
+	 * Compute the signed angle between two vectors.
+	 * 
+	 * @param x1
+	 * @param y1
+	 * @param x2
+	 * @param y2
+	 * @return the angle between <code>-PI</code> and <code>PI</code>.
+	 */
+	public static float signedAngle(float x1, float y1, float x2, float y2) {
+		float length1 = (float)Math.sqrt(x1 * x1 + y1 * y1);
+		float length2 = (float)Math.sqrt(x2 * x2 + y2 * y2);
+
+		if ((length1 == 0f) || (length2 == 0f))
+			return Float.NaN;
+
+		float cx1 = x1;
+		float cy1 = y1;
+		float cx2 = x2;
+		float cy2 = y2;
+
+		// A and B are normalized
+		if (length1 != 1) {
+			cx1 /= length1;
+			cy1 /= length1;
+		}
+
+		if (length2 != 1) {
+			cx2 /= length2;
+			cy2 /= length2;
+		}
+
+		/*
+		 * // First method // Angle // A . B = |A|.|B|.cos(theta) = cos(theta) float dot = x1 * x2 + y1 * y2; float angle = Math.acos(dot);
+		 * 
+		 * // On which side of A, B is located? if ((dot > -1) && (dot < 1)) { dot = MathUtil.determinant(x2, y2, x1, y1); if (dot < 0) angle = -angle; }
+		 */
+
+		// Second method
+		// A . B = |A|.|B|.cos(theta) = cos(theta)
+		float cos = cx1 * cx2 + cy1 * cy2;
+		// A x B = |A|.|B|.sin(theta).N = sin(theta) (where N is the unit vector perpendicular to plane AB)
+		float sin = cx1 * cy2 - cy1 * cx2;
+
+		float angle = (float)Math.atan2(sin, cos);
+
+		return angle;
+	}
+
+	/** Return the trigonometric angle of a vector.
+	 *  The vector is from the first point to the
+	 *  second point.
+	 *  <p>
+	 *  The trigonometric angle is the signed angle between
+	 *  the vectors (1;0) and (p2.x-p1.x;p2.y-p1.y).
+	 *
+	 * @param p1 first point.
+	 * @param p2 second point.
+	 * @return the trigonometric angle in radians in [-PI;PI].
+	 */
+	public static final float angleOfVector( Point2D p1, Point2D p2 ) {
+		return signedAngle(
+				1, 0, 
+				p2.getX() - p1.getX(),
+				p2.getY() - p1.getY());
+	}
+
+	/** Return the trigonometric angle of a vector.
+	 *  The vector is from the first point to the
+	 *  second point.
+	 *  <p>
+	 *  The trigonometric angle is the signed angle between
+	 *  the vectors (1;0) and (x2-x1;y2-y1).
+	 *
+	 * @param x1 is the coordinate of the vector origin point.
+	 * @param y1 is the coordinate of the vector origin point.
+	 * @param x2 is the coordinate of the vector target point.
+	 * @param y2 is the coordinate of the vector target point.
+	 * @return the trigonometric angle in radians in [-PI;PI].
+	 */
+	public static final float angleOfVector(float x1, float y1, float x2, float y2) {
+		return signedAngle(
+				1, 0, 
+				x2-x1, y2-y1);
+	}
+
+	/** Return the trigonometric angle of a vector.
+	 *  The vector is from the first point to the
+	 *  second point.
+	 *  <p>
+	 *  The trigonometric angle is the signed angle between
+	 *  the vectors (1;0) and (x;y).
+	 *
+	 * @param x is the coordinate of the vector.
+	 * @param y is the coordinate of the vector.
+	 * @return the trigonometric angle in radians in [-PI;PI].
+	 */
+	public static final float angleOfVector(float x, float y) {
+		return signedAngle(
+				1, 0, 
+				x, y);
+	}
+
+	/** Replies if a point is closed to a segment.
+	 *
+	 * @param x1 horizontal location of the first-segment begining.
+	 * @param y1 vertical location of the first-segment ending.
+	 * @param x2 horizontal location of the second-segment begining.
+	 * @param y2 vertical location of the second-segment ending.
+	 * @param x horizontal location of the point.
+	 * @param y vertical location of the point.
+	 * @param hitDistance is the maximal hitting distance.
+	 * @return <code>true</code> if the point and the
+	 *         line have closed locations.
+	 */
+	public static boolean isPointClosedToSegment( float x1, float y1, 
+			float x2, float y2, 
+			float x, float y, float hitDistance ) {
+		return ( distancePointToSegment(x, y, x1, y1, x2, y2) < hitDistance ) ;
+	}
+
+	/** Replies if a point is closed to a line.
+	 *
+	 * @param x1 horizontal location of the first-line begining.
+	 * @param y1 vertical location of the first-line ending.
+	 * @param x2 horizontal location of the second-line begining.
+	 * @param y2 vertical location of the second-line ending.
+	 * @param x horizontal location of the point.
+	 * @param y vertical location of the point.
+	 * @param hitDistance is the maximal hitting distance.
+	 * @return <code>true</code> if the point and the
+	 *         line have closed locations.
+	 */
+	public static boolean isPointClosedToLine( float x1, float y1, 
+			float x2, float y2, 
+			float x, float y, float hitDistance ) {
+		return ( distancePointToLine(x, y, x1, y1, x2, y2) < hitDistance ) ;
+	}
+
+	/** Replies the metrics from inches.
+	 *
+	 * @param i the inch value
+	 * @return a value in centimeters
+	 */
+	public static float inchToMetric( float i ) {
+		return i / 0.3937f ;
+	}
+
+	/** Replies the inches from metrics.
+	 *
+	 * @param m the metric value
+	 * @return a value in inches
+	 */
+	public static float metricToInch( float m ) {
+		return m * 0.3937f ;
+	}
+
+	/** Replies the <var>value</var> clamped in
+	 * the specified interval assuming the
+	 * it is a angle in radians.
+	 *
+	 * @param value is the value to clamp.
+	 * @param min is the minimal allowed value.
+	 * @param max is the maximal allowed value.
+	 * @return the clamped value.
+	 */
+	public static float clampAngle( float value, float min, float max ) {
+		assert(min<=max);
+		float v = value;
+		while (v>max) {
+			v -= 2*Math.PI;
+		}
+		if (v<min) return min;
+		return v;
+	}
+
+	/** Replies the <var>value</var> clamped to
+	 * the nearest bounds.
+	 * If |<var>value</var>-<var>minBounds</var>| &gt;
+	 * |<var>value</var>-<var>maxBounds</var>| then the
+	 * returned value is <var>maxBounds</var>; otherwise
+	 * it is <var>minBounds</var>.
+	 *
+	 * @param value is the value to clamp.
+	 * @param minBounds is the minimal allowed value.
+	 * @param maxBounds is the maximal allowed value.
+	 * @return <var>minBounds</var> or <var>maxBounds</var>.
+	 */
+	public static float clampToNearestBounds( float value, float minBounds, float maxBounds ) {
+		assert(minBounds<=maxBounds);
+		float center = (minBounds+maxBounds) / 2f;
+		if (value<=center) return minBounds;
+		return maxBounds;
+	}
+
+	/**
+	 * Replies one position factor for the intersection point between two lines.
+	 * <p>
+	 * Let line equations for L1 and L2:<br>
+	 * <code>L1: P1 + factor1 * (P2-P1)</code><br>
+	 * <code>L2: P3 + factor2 * (P4-P3)</code><br>
+	 * If lines are intersecting, then<br>
+	 * <code>P1 + factor1 * (P2-P1) = P3 + factor2 * (P4-P3)</code>
+	 * <p>
+	 * This function computes and replies <code>factor1</code>.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point of the first segment.
+	 * @param y1
+	 *            is the Y coordinate of the first point of the first segment.
+	 * @param x2
+	 *            is the X coordinate of the second point of the first segment.
+	 * @param y2
+	 *            is the Y coordinate of the second point of the first segment.
+	 * @param x3
+	 *            is the X coordinate of the first point of the second segment.
+	 * @param y3
+	 *            is the Y coordinate of the first point of the second segment.
+	 * @param x4
+	 *            is the X coordinate of the second point of the second segment.
+	 * @param y4
+	 *            is the Y coordinate of the second point of the second segment.
+	 * @return <code>factor1</code> or {@link Float#NaN} if no intersection.
+	 * @since 3.0
+	 */
+	public static float getSegmentSegmentIntersectionFactor(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		float X1 = x2 - x1;
+		float Y1 = y2 - y1;
+		float X2 = x4 - x3;
+		float Y2 = y4 - y3;
+
+		// determinant is zero when parallel = det(L1,L2)
+		float det = determinant(X1, Y1, X2, Y2);
+		if (det == 0.)
+			return Float.NaN;
+
+		// Given line equations:
+		// Pa = P1 + ua (P2-P1), and
+		// Pb = P3 + ub (P4-P3)
+		// and
+		// V = (P1-P3)
+		// then
+		// ua = det(L2,V) / det(L1,L2)
+		// ub = det(L1,V) / det(L1,L2)
+		float u = determinant(X1, Y1, x1 - x3, y1 - y3) / det;
+		if (u < 0. || u > 1.)
+			return Float.NaN;
+		u = determinant(X2, Y2, x1 - x3, y1 - y3) / det;
+		return (u < 0. || u > 1.) ? Float.NaN : u;
+	}
+
+	/** Compute the determinant of two vectors.
+	 * <p>
+	 * <pre><code>det(X1,X2) = |X1|.|X2|.sin(a)</code></pre>
+	 * where <code>X1</code> and <code>X2</code> are two vectors
+	 * and <code>a</code> is the angle between <code>X1</code>
+	 * and <code>X2</code>. 
+	 * 
+	 * @param x1
+	 * @param y1
+	 * @param x2
+	 * @param y2
+	 * @return the determinant
+	 */
+	public static float determinant(float x1, float y1, float x2, float y2) {
+		return x1*y2 - x2*y1;
+	}
+
+	/**
+	 * Replies the intersection point between two segments.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point of the first segment.
+	 * @param y1
+	 *            is the Y coordinate of the first point of the first segment.
+	 * @param x2
+	 *            is the X coordinate of the second point of the first segment.
+	 * @param y2
+	 *            is the Y coordinate of the second point of the first segment.
+	 * @param x3
+	 *            is the X coordinate of the first point of the second segment.
+	 * @param y3
+	 *            is the Y coordinate of the first point of the second segment.
+	 * @param x4
+	 *            is the X coordinate of the second point of the second segment.
+	 * @param y4
+	 *            is the Y coordinate of the second point of the second segment.
+	 * @return the intersection point or <code>null</code> if none.
+	 */
+	public static Point2D getSegmentSegmentIntersectionPoint(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		float m = getSegmentSegmentIntersectionFactor(x1, y1, x2, y2, x3, y3, x4, y4);
+		if (Float.isNaN(m))
+			return null;
+		return new Point2f(x1 + m * (x2 - x1), y1 + m * (y2 - y1));
+	}
+
+	/** Compute the interpolate point between the two points.
+	 * 
+	 * @param p1
+	 * @param p2
+	 * @param factor is between 0 and 1; 0 for p1, and 1 for p2.
+	 * @return the interpolate point.
+	 */
+	public static Point2D interpolate(Point2D p1, Point2D p2, float factor) {
+		return interpolate(p1.getX(), p1.getY(), p2.getX(), p2.getY(), factor);
+	}
+
+	/** Compute the interpolate point between the two points.
+	 * 
+	 * @param p1x
+	 * @param p1y
+	 * @param p2x
+	 * @param p2y
+	 * @param factor is between 0 and 1; 0 for p1, and 1 for p2.
+	 * @return the interpolate point.
+	 */
+	public static Point2D interpolate(float p1x, float p1y, float p2x, float p2y, float factor) {
+		float f = (factor<0f) ? 0f : factor;
+		if (f>1f) f = 1f;
+		float vx = p2x - p1x;
+		float vy = p2y - p1y;
+		return new Point2f(
+				p1x + factor * vx,
+				p1y + factor * vy);
+	}
+
+	/** Compute the dot product of two vectors.
+	 * 
+	 * @param x1
+	 * @param y1
+	 * @param x2
+	 * @param y2
+	 * @return the dot product.
+	 */
+	public static float dotProduct(float x1, float y1, float x2, float y2) {
+		return x1*x2 + y1*y2;
+	}
+
+	/**
+	 * Replies the relative counterclockwise (CCW) of a segment against a point. Returns an indicator of where the specified point {@code (px,py)} lies with respect to the line segment from {@code (x1,y1)} to {@code (x2,y2)}. The return value can be either 1, -1, or 0 and indicates in which direction the specified line must pivot around its first end point, {@code (x1,y1)}, in order to point at the specified point {@code (px,py)}.
+	 * In other words, given three point P1, P2, and P, is the segments (P1-P2-P) a counterclockwise turn?
+	 * <p>
+	 * A return value of 1 indicates that the line segment must turn in the direction that takes the positive X axis towards the negative Y axis. In the default coordinate system used by Java 2D, this direction is counterclockwise.
+	 * <p>
+	 * A return value of -1 indicates that the line segment must turn in the direction that takes the positive X axis towards the positive Y axis. In the default coordinate system, this direction is clockwise.
+	 * <p>
+	 * A return value of 0 indicates that the point lies exactly on the line segment. Note that an indicator value of 0 is rare and not useful for determining colinearity because of floating point rounding issues.
+	 * <p>
+	 * If the point is colinear with the line segment, but not between the end points, then the value will be -1 if the point lies "beyond {@code (x1,y1)}" or 1 if the point lies "beyond {@code (x2,y2)}".
+	 * 
+	 * @param x1
+	 *            the X coordinate of the start point of the specified line segment
+	 * @param y1
+	 *            the Y coordinate of the start point of the specified line segment
+	 * @param x2
+	 *            the X coordinate of the end point of the specified line segment
+	 * @param y2
+	 *            the Y coordinate of the end point of the specified line segment
+	 * @param px
+	 *            the X coordinate of the specified point to be compared with the specified line segment
+	 * @param py
+	 *            the Y coordinate of the specified point to be compared with the specified line segment
+	 * @param approximateZero
+	 *            indicates if zero may be approximated or not.
+	 * @return an integer that indicates the position of the third specified coordinates with respect to the line segment formed by the first two specified coordinates.
+	 * @see #relativeDistancePointToLine(float, float, float, float, float, float)
+	 */
+	public static int ccw(float x1, float y1, float x2, float y2, float px, float py, boolean approximateZero) {
+		float cx2 = x2 - x1;
+		float cy2 = y2 - y1;
+		float cpx = px - x1;
+		float cpy = py - y1;
+		float ccw = cpx * cy2 - cpy * cx2;
+		if ((approximateZero && isEpsilonZero(ccw)) || (!approximateZero && ccw == 0.)) {
+			// The point is colinear, classify based on which side of
+			// the segment the point falls on. We can calculate a
+			// relative value using the projection of px,py onto the
+			// segment - a negative value indicates the point projects
+			// outside of the segment in the direction of the particular
+			// endpoint used as the origin for the projection.
+			ccw = cpx * cx2 + cpy * cy2;
+			if (ccw > 0.) {
+				// Reverse the projection to be relative to the original x2,y2
+				// x2 and y2 are simply negated.
+				// px and py need to have (x2 - x1) or (y2 - y1) subtracted
+				// from them (based on the original values)
+				// Since we really want to get a positive answer when the
+				// point is "beyond (x2,y2)", then we want to calculate
+				// the inverse anyway - thus we leave x2 & y2 negated.
+				cpx -= cx2;
+				cpy -= cy2;
+				ccw = cpx * cx2 + cpy * cy2;
+				if (ccw < 0f) {
+					ccw = 0f;
+				}
+			}
+		}
+		return (ccw < 0f) ? -1 : ((ccw > 0f) ? 1 : 0);
+	}
+
+	/**
+	 * Replies on which side of a line the given point is located.
+	 * <p>
+	 * A return value of 1 indicates that the line segment must turn in the direction
+	 * that takes the positive X axis towards the negative Y axis. In the default
+	 * coordinate system used by Java 2D, this direction is counterclockwise.
+	 * <p>
+	 * A return value of -1 indicates that the line segment must turn in the direction that takes the positive X axis towards the positive Y axis. In the default coordinate system, this direction is clockwise.
+	 * <p>
+	 * A return value of 0 indicates that the point lies exactly on the line segment. Note that an indicator value of 0 is rare and not useful for determining colinearity because of floating point rounding issues.
+	 * <p>
+	 * This function uses the equal-to-zero test with the error {@link #EPSILON}.
+	 * 
+	 * @param x1
+	 *            the X coordinate of the start point of the specified line segment
+	 * @param y1
+	 *            the Y coordinate of the start point of the specified line segment
+	 * @param x2
+	 *            the X coordinate of the end point of the specified line segment
+	 * @param y2
+	 *            the Y coordinate of the end point of the specified line segment
+	 * @param px
+	 *            the X coordinate of the specified point to be compared with the specified line segment
+	 * @param py
+	 *            the Y coordinate of the specified point to be compared with the specified line segment
+	 * @param approximateZero
+	 *            indicates if zero may be approximated or not.
+	 * @return an integer that indicates the position of the third specified coordinates with respect to the line segment formed by the first two specified coordinates.
+	 * @see #relativeDistancePointToLine(float, float, float, float, float, float)
+	 * @see #isEpsilonZero(float)
+	 */
+	public static int sidePointLine(float x1, float y1, float x2, float y2, float px, float py, boolean approximateZero) {
+		float cx2 = x2 - x1;
+		float cy2 = y2 - y1;
+		float cpx = px - x1;
+		float cpy = py - y1;
+		float side = cpx * cy2 - cpy * cx2;
+		if (approximateZero && side!=0f && isEpsilonZero(side)) {
+			side = 0f;
+		}
+		return (side < 0f) ? -1 : ((side > 0f) ? 1 : 0);
+	}
+
+	/**
+	 * Replies the relative distance from the given point to the given line.
+	 * The replied distance may be negative, depending on which side of 
+	 * the line the point is.
+	 * 
+	 * @param x1
+	 *            the X coordinate of the start point of the specified line segment
+	 * @param y1
+	 *            the Y coordinate of the start point of the specified line segment
+	 * @param x2
+	 *            the X coordinate of the end point of the specified line segment
+	 * @param y2
+	 *            the Y coordinate of the end point of the specified line segment
+	 * @param px
+	 *            the X coordinate of the specified point to be compared with the specified line segment
+	 * @param py
+	 *            the Y coordinate of the specified point to be compared with the specified line segment
+	 * @return the positive or negative distance from the point to the line
+	 * @see #ccw(float, float, float, float, float, float, boolean)
+	 * @see #sidePointLine(float, float, float, float, float, float, boolean)
+	 * @see #distancePointToLine(float, float, float, float, float, float)
+	 */
+	public static float relativeDistancePointToLine(float x1, float y1, float x2, float y2, float px, float py) {
+		float r_denomenator = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
+		if (r_denomenator==0.) return distancePointToPoint(px, py, x1, y1);
+		float s = ((y1-py)*(x2-x1)-(x1-px)*(y2-y1) ) / r_denomenator;
+		return (float)(s * Math.sqrt(r_denomenator));
+	}
+
+	/** Compute the intersection of two lines specified
+	 * by the specified points and vectors.
+	 * 
+	 * @param p1 is a point of the first line.
+	 * @param v1 is the direction of the first line.
+	 * @param p2 is a point of the second line.
+	 * @param v2 is the direction of the second line.
+	 * @return the intersection point or <code>null</code> if there is no intersection.
+	 */
+	public static Point2D computeLineIntersection(Point2D p1, Vector2D v1, Point2D p2, Vector2D v2) {
+		float x1 = p1.getX();
+		float y1 = p1.getY();
+		float x2 = x1 + v1.getX();
+		float y2 = y1 + v1.getY();
+		float x3 = p2.getX();
+		float y3 = p2.getY();
+		float x4 = x3 + v2.getX();
+		float y4 = y3 + v2.getY();
+		float denom = (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1);
+		if (denom==0.) return null;
+		float ua = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3));
+		float ub = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3));
+		if (ua==ub) return null;
+		ua = ua / denom;
+		return new Point2f(
+				x1 + ua * (x2 - x1),
+				y1 + ua * (y2 - y1));
+	}
+
+	/**
+	 * Replies the projection a point on a segment.
+	 * 
+	 * @param px
+	 *            is the coordiante of the point to project
+	 * @param py
+	 *            is the coordiante of the point to project
+	 * @param s1x
+	 *            is the x-coordinate of the first line point.
+	 * @param s1y
+	 *            is the y-coordinate of the first line point.
+	 * @param s2x
+	 *            is the x-coordinate of the second line point.
+	 * @param s2y
+	 *            is the y-coordinate of the second line point.
+	 * @return the projection of the specified point on the line. If 
+	 * equal to {@code 0}, the projection is equal to the first segment point. 
+	 * If equal to {@code 1}, the projection is equal to the second segment point. 
+	 * If inside {@code ]0;1[}, the projection is between the two segment points. 
+	 * If inside {@code ]-inf;0[}, the projection is outside on the side of the 
+	 * first segment point. If inside {@code ]1;+inf[}, the projection is 
+	 * outside on the side of the second segment point.
+	 */
+	public static float projectsPointOnLine(float px, float py, float s1x, float s1y, float s2x, float s2y) {
+		float r_numerator = (px-s1x)*(s2x-s1x) + (py-s1y)*(s2y-s1y);
+		float r_denomenator = (s2x-s1x)*(s2x-s1x) + (s2y-s1y)*(s2y-s1y);
+		return r_numerator / r_denomenator;
+	}
+
+	/**
+	 * Replies the position factory for the intersection point between two lines.
+	 * <p>
+	 * Let line equations for L1 and L2:<br>
+	 * <code>L1: P1 + factor1 * (P2-P1)</code><br>
+	 * <code>L2: P3 + factor2 * (P4-P3)</code><br>
+	 * If lines are intersecting, then<br>
+	 * <code>P1 + factor1 * (P2-P1) = P3 + factor2 * (P4-P3)</code>
+	 * <p>
+	 * This function computes and replies <code>factor1</code>.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point of the first line.
+	 * @param y1
+	 *            is the Y coordinate of the first point of the first line.
+	 * @param x2
+	 *            is the X coordinate of the second point of the first line.
+	 * @param y2
+	 *            is the Y coordinate of the second point of the first line.
+	 * @param x3
+	 *            is the X coordinate of the first point of the second line.
+	 * @param y3
+	 *            is the Y coordinate of the first point of the second line.
+	 * @param x4
+	 *            is the X coordinate of the second point of the second line.
+	 * @param y4
+	 *            is the Y coordinate of the second point of the second line.
+	 * @return <code>factor1</code> or {@link Float#NaN} if no intersection.
+	 */
+	public static float getLineLineIntersectionFactor(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		float X1 = x2 - x1;
+		float Y1 = y2 - y1;
+		float X2 = x4 - x3;
+		float Y2 = y4 - y3;
+
+		// determinant is zero when parallel = det(L1,L2)
+		float det = MathUtil.determinant(X1, Y1, X2, Y2);
+		if (det == 0.)
+			return Float.NaN;
+
+		// Given line equations:
+		// Pa = P1 + ua (P2-P1), and
+		// Pb = P3 + ub (P4-P3)
+		// and
+		// V = (P1-P3)
+		// then
+		// ua = det(L2,V) / det(L1,L2)
+		// ub = det(L1,V) / det(L1,L2)
+		return MathUtil.determinant(X2, Y2, x1 - x3, y1 - y3) / det;
+	}
+
+	/**
+	 * Replies if the given point is inside the given ellipse.
+	 * 
+	 * @param px is the point to test.
+	 * @param py is the point to test.
+	 * @param ellx is the min corner of the ellipse.
+	 * @param elly is the min corner of the ellipse.
+	 * @param ellw is the width of the ellipse.
+	 * @param ellh is the height of the ellipse.
+	 * @return <code>true</code> if the point is inside the ellipse;
+	 * <code>false</code> if not.
+	 */
+	public static boolean isPointInEllipse(float px, float py, float ellx, float elly, float ellw, float ellh) {
+		// Copied from AWT Ellipse2D
+
+		// Normalize the coordinates compared to the ellipse
+		// having a center at 0,0 and a radius of 0.5.
+		if (ellw <= 0f || ellh <= 0f) {
+			return false;
+		}
+		float normx = (px - ellx) / ellw - 0.5f;
+		float normy = (py - elly) / ellh - 0.5f;
+		return (normx * normx + normy * normy) < 0.25f;
+	}
+
+	/**
+	 * Replies if the given point is inside the given ellipse.
+	 * 
+	 * @param px is the point to test.
+	 * @param py is the point to test.
+	 * @param cx is the center of the circle.
+	 * @param cy is the center of the circle.
+	 * @param radius is the radius of the circle.
+	 * @return <code>true</code> if the point is inside the circle;
+	 * <code>false</code> if not.
+	 */
+	public static boolean isPointInCircle(float px, float py, float cx, float cy, float radius) {
+		return distanceSquaredPointToPoint(
+				px, py,
+				cx, cy) <= (radius * radius);
+	}
+
+	/** Replies the closest point from the given point in the solid ellipse.
+	 * A solid ellipse is an ellipse with a border and an interior area.
+	 * 
+	 * @param px is the coordinate of the point.
+	 * @param py is the coordinate of the point.
+	 * @param ex is the coordinate of the min corner of the ellipse
+	 * @param ey is the coordinate of the min corner of the ellipse
+	 * @param ew is the width of the ellipse
+	 * @param eh is the height of the ellipse
+	 * @return the closest point in the ellipse
+	 * @see #getClosestPointToSolidEllipse(float, float, float, float, float, float, boolean)
+	 * @see #getClosestPointToShallowEllipse(float, float, float, float, float, float)
+	 */
+	public static Point2D getClosestPointToSolidEllipse(float px, float py, float ex, float ey, float ew, float eh) {
+		return getClosestPointToSolidEllipse(px, py, ex, ey, ew, eh, false);
+	}
+
+	/** Replies the closest point from the given point in the solid ellipse.
+	 * A solid ellipse is an ellipse with a border and an interior area.
+	 * 
+	 * @param px is the coordinate of the point.
+	 * @param py is the coordinate of the point.
+	 * @param ex is the coordinate of the min corner of the ellipse
+	 * @param ey is the coordinate of the min corner of the ellipse
+	 * @param ew is the width of the ellipse
+	 * @param eh is the height of the ellipse
+	 * @param returnNullWhenInside indicates if a <code>null</code> value
+	 * may be returned when the point is inside the ellipse, if
+	 * <code>true</code>; or a point all the time if <code>false</code>.
+	 * @return the closest point in the ellipse
+	 * @see #getClosestPointToShallowEllipse(float, float, float, float, float, float)
+	 */
+	public static Point2D getClosestPointToSolidEllipse(float px, float py, float ex, float ey, float ew, float eh, boolean returnNullWhenInside) {
+		float x, y;
+		if (ew<=0f || eh<=0f) {
+			x = ex;
+			y = ey;
+		}
+		else {
+			// Normalize the coordinates compared to the ellipse
+			// having a center at 0,0 and a radius of 0.5.
+			float normx = (px - ex) / ew - 0.5f;
+			float normy = (py - ey) / eh - 0.5f;
+			if ((normx * normx + normy * normy) < 0.25f) {
+				// The point is inside the ellipse
+				if (returnNullWhenInside) return null;
+				x = px;
+				y = py;
+			}
+			else {
+				// Compute the intersection between the ellipse
+				// centered on (0;0) and the line (0;0)-(x0;y0)
+				float a = ew / 2f;
+				float b = eh / 2f;
+				float x0 = px - (ex + a);
+				float y0 = py - (ey + b);
+
+				float denom = a*a*y0*y0 + b*b*x0*x0;
+				assert(denom>0f); // because the "inside"-test should discard this case.
+
+				denom = (float)Math.sqrt(denom);
+				float factor = (a * b) / denom;
+				x = factor * x0;
+				y = factor * y0;
+
+				// Translate the point to the original coordinate system
+				x += (ex + a);
+				y += (ey + b);
+			}
+		}
+		return new Point2f(x, y);
+	}
+
+	/** Replies the closest point from the given point in the shallow ellipse.
+	 * A shallow ellipse is an ellipse with a border and not an interior area.
+	 * 
+	 * @param px is the coordinate of the point.
+	 * @param py is the coordinate of the point.
+	 * @param ex is the coordinate of the min corner of the ellipse
+	 * @param ey is the coordinate of the min corner of the ellipse
+	 * @param ew is the width of the ellipse
+	 * @param eh is the height of the ellipse
+	 * @return the closest point in the ellipse, or <code>null</code> if 
+	 * the given point is exactly at the center of the ellipse.
+	 */
+	public static Point2D getClosestPointToShallowEllipse(float px, float py, float ex, float ey, float ew, float eh) {
+		float x, y;
+		if (ew<=0f || eh<=0f) {
+			x = ex;
+			y = ey;
+		}
+		else {
+			// Compute the intersection between the ellipse
+			// centered on (0;0) and the line (0;0)-(x0;y0)
+			float a = ew / 2f;
+			float b = eh / 2f;
+			float x0 = px - (ex + a);
+			float y0 = py - (ey + b);
+
+			float denom = a*a*y0*y0 + b*b*x0*x0;
+			if (denom==0f) {
+				// The point is at the center of the ellipse.
+				// Replies allways the same point.
+				return null;
+			}
+
+			denom = (float)Math.sqrt(denom);
+			float factor = (a * b) / denom;
+			x = factor * x0;
+			y = factor * y0;
+
+			// Translate the point to the original coordinate system
+			x += (ex + a);
+			y += (ey + b);
+		}
+		return new Point2f(x, y);
+	}
+
+	/**
+	 * Replies if two lines are parallel.
+	 * <p>
+	 * The given two lines are described respectivaly by two points, i.e. {@code (x1,y1)} and {@code (x2,y2)} for the first line, and {@code (x3,y3)} and {@code (x4,y4)} for the second line.
+	 * <p>
+	 * If you are interested to test if the two lines are colinear, see {@link #isCollinearLines(float, float, float, float, float, float, float, float)}.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point of the first line.
+	 * @param y1
+	 *            is the Y coordinate of the first point of the first line.
+	 * @param x2
+	 *            is the X coordinate of the second point of the first line.
+	 * @param y2
+	 *            is the Y coordinate of the second point of the first line.
+	 * @param x3
+	 *            is the X coordinate of the first point of the second line.
+	 * @param y3
+	 *            is the Y coordinate of the first point of the second line.
+	 * @param x4
+	 *            is the X coordinate of the second point of the second line.
+	 * @param y4
+	 *            is the Y coordinate of the second point of the second line.
+	 * @return <code>true</code> if the two given lines are parallel.
+	 * @see #isCollinearLines(float, float, float, float, float, float, float, float)
+	 * @since 3.0
+	 */
+	public static boolean isParallelLines(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		return isCollinearVectors(x2 - x1, y2 - y1, x4 - x3, y4 - y3);
+	}
+
+	/**
+	 * Replies if two lines are parallel.
+	 * <p>
+	 * The given two lines are described respectivaly by two points, i.e. {@code (x1,y1,z1)} and {@code (x2,y2,z2)} for the first line, and {@code (x3,y3,z3)} and {@code (x4,y4,z4)} for the second line.
+	 * <p>
+	 * Line through (x<sub>0</sub>,y<sub>0</sub>,z<sub>0</sub>) in direction (a<sub>0</sub>,b<sub>0</sub>,c<sub>0</sub>) and line through (x<sub>1</sub>,yx<sub>1</sub>,zx<sub>1</sub>) in direction (ax<sub>1</sub>,bx<sub>1</sub>,cx<sub>1</sub>): <center><img src="doc-files/parallellines3d.gif" alt="Parallel lines"></center>
+	 * <p>
+	 * Two lines specified by point and direction are coplanar if and only if the determinant in the numerator is zero. In this case they are concurrent (if the denominator is nonzero) or parallel (if the denominator is zero).
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point of the first line.
+	 * @param y1
+	 *            is the Y coordinate of the first point of the first line.
+	 * @param z1
+	 *            is the Z coordinate of the first point of the first line.
+	 * @param x2
+	 *            is the X coordinate of the second point of the first line.
+	 * @param y2
+	 *            is the Y coordinate of the second point of the first line.
+	 * @param z2
+	 *            is the Z coordinate of the second point of the first line.
+	 * @param x3
+	 *            is the X coordinate of the first point of the second line.
+	 * @param y3
+	 *            is the Y coordinate of the first point of the second line.
+	 * @param z3
+	 *            is the Z coordinate of the first point of the second line.
+	 * @param x4
+	 *            is the X coordinate of the second point of the second line.
+	 * @param y4
+	 *            is the Y coordinate of the second point of the second line.
+	 * @param z4
+	 *            is the Z coordinate of the second point of the second line.
+	 * @return <code>true</code> if the two given lines are parallel.
+	 * @since 3.0
+	 */
+	public static boolean isParallelLines(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4) {
+		return isCollinearVectors(x2 - x1, y2 - y1, z2 - z1, x4 - x3, y4 - y3, z4 - z3);
+	}
+
+	/**
+	 * Replies if three points are colinear, ie. one the same line.
+	 * <p>
+	 * Trival approach is: points are collinear iff |AB| + |AC| = |BC|, where A B C are the three points.
+	 * <p>
+	 * This function uses the equal-to-zero test with the error {@link #EPSILON}.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point
+	 * @param y1
+	 *            is the Y coordinate of the first point
+	 * @param x2
+	 *            is the X coordinate of the second point
+	 * @param y2
+	 *            is the Y coordinate of the second point
+	 * @param x3
+	 *            is the X coordinate of the third point
+	 * @param y3
+	 *            is the Y coordinate of the third point
+	 * @return <code>true</code> if the three given points are colinear.
+	 * @since 3.0
+	 * @see #isEpsilonZero(float)
+	 */
+	public static boolean isCollinearPoints(float x1, float y1, float x2, float y2, float x3, float y3) {
+		// Test if three points are colinears
+		// iff det( [ x1 x2 x3 ]
+		// [ y1 y2 y3 ]
+		// [ 1 1 1 ] ) = 0
+		// Do not invoked MathUtil.determinant() to limit computations.
+		return isEpsilonZero(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
+	}
+
+	/**
+	 * Replies if three points are colinear, ie. one the same line.
+	 * <p>
+	 * Trival approach is: points are collinear iff |AB| + |AC| = |BC|, where A B C are the three points.
+	 * <p>
+	 * This function uses the equal-to-zero test with the error {@link #EPSILON}.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point
+	 * @param y1
+	 *            is the Y coordinate of the first point
+	 * @param z1
+	 *            is the Z coordinate of the first point
+	 * @param x2
+	 *            is the X coordinate of the second point
+	 * @param y2
+	 *            is the Y coordinate of the second point
+	 * @param z2
+	 *            is the Z coordinate of the second point
+	 * @param x3
+	 *            is the X coordinate of the third point
+	 * @param y3
+	 *            is the Y coordinate of the third point
+	 * @param z3
+	 *            is the Z coordinate of the third point
+	 * @return <code>true</code> if the three given points are colinear.
+	 * @since 3.0
+	 * @see #isEpsilonZero(float)
+	 */
+	public static boolean isCollinearPoints(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) {
+		float dx1 = x2 - x1;
+		float dy1 = y2 - y1;
+		float dz1 = z2 - z1;
+		float dx2 = x3 - x1;
+		float dy2 = y3 - y1;
+		float dz2 = z3 - z1;
+
+		float cx = dy1 * dz2 - dy2 * dz1;
+		float cy = dx2 * dz1 - dx1 * dz2;
+		float cz = dx1 * dy2 - dx2 * dy1;
+
+		float sum = cx * cx + cy * cy + cz * cz;
+
+		return isEpsilonZero(sum);
+	}
+
+	/**
+	 * Replies if two vectors are colinear.
+	 * <p>
+	 * This function uses the equal-to-zero test with the error {@link #EPSILON}.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first vector
+	 * @param y1
+	 *            is the Y coordinate of the first vector
+	 * @param x2
+	 *            is the X coordinate of the second vector
+	 * @param y2
+	 *            is the Y coordinate of the second vector
+	 * @return <code>true</code> if the two given vectors are colinear.
+	 * @since 3.0
+	 * @see #isEpsilonZero(float)
+	 */
+	public static boolean isCollinearVectors(float x1, float y1, float x2, float y2) {
+		// Test if three points are colinears
+		// iff det( [ x1 x2 x3 ]
+		// [ y1 y2 y3 ]
+		// [ 1 1 1 ] ) = 0
+		// Do not invoked MathUtil.determinant() to limit computation consumption.
+		return isEpsilonZero(x1 * y2 - x2 * y1);
+	}
+
+	/**
+	 * Replies if two vectors are colinear.
+	 * <p>
+	 * This function uses the equal-to-zero test with the error {@link #EPSILON}.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first vector
+	 * @param y1
+	 *            is the Y coordinate of the first vector
+	 * @param z1
+	 *            is the Z coordinate of the first vector
+	 * @param x2
+	 *            is the X coordinate of the second vector
+	 * @param y2
+	 *            is the Y coordinate of the second vector
+	 * @param z2
+	 *            is the Z coordinate of the second vector
+	 * @return <code>true</code> if the two given vectors are colinear.
+	 * @since 3.0
+	 * @see #isEpsilonZero(float)
+	 */
+	public static boolean isCollinearVectors(float x1, float y1, float z1, float x2, float y2, float z2) {
+		// Cross product
+		float cx = y1 * z2 - z1 * y2;
+		float cy = z1 * x2 - x1 * z2;
+		float cz = x1 * y2 - y1 * x2;
+
+		float sum = cx * cx + cy * cy + cz * cz;
+
+		return isEpsilonZero(sum);
+	}
+
+	/**
+	 * Replies if two lines are colinear.
+	 * <p>
+	 * The given two lines are described respectivaly by two points, i.e. {@code (x1,y1)} and {@code (x2,y2)} for the first line, and {@code (x3,y3)} and {@code (x4,y4)} for the second line.
+	 * <p>
+	 * If you are interested to test if the two lines are parallel, see {@link #isParallelLines(float, float, float, float, float, float, float, float)}.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point of the first line.
+	 * @param y1
+	 *            is the Y coordinate of the first point of the first line.
+	 * @param x2
+	 *            is the X coordinate of the second point of the first line.
+	 * @param y2
+	 *            is the Y coordinate of the second point of the first line.
+	 * @param x3
+	 *            is the X coordinate of the first point of the second line.
+	 * @param y3
+	 *            is the Y coordinate of the first point of the second line.
+	 * @param x4
+	 *            is the X coordinate of the second point of the second line.
+	 * @param y4
+	 *            is the Y coordinate of the second point of the second line.
+	 * @return <code>true</code> if the two given lines are collinear.
+	 * @see #isParallelLines(float, float, float, float, float, float, float, float)
+	 * @see #isCollinearPoints(float, float, float, float, float, float)
+	 */
+	public static boolean isCollinearLines(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		return (isParallelLines(x1, y1, x2, y2, x3, y3, x4, y4) && isCollinearPoints(x1, y1, x2, y2, x3, y3));
+	}
+
+	/**
+	 * Replies if two lines are colinear.
+	 * <p>
+	 * The given two lines are described respectivaly by two points, i.e. {@code (x1,y1,z1)} and {@code (x2,y2,z2)} for the first line, and {@code (x3,y3,z3)} and {@code (x4,y4,z4)} for the second line.
+	 * <p>
+	 * If you are interested to test if the two lines are parallel, see {@link #isParallelLines(float, float, float, float, float, float, float, float, float, float, float, float)}.
+	 * 
+	 * @param x1
+	 *            is the X coordinate of the first point of the first line.
+	 * @param y1
+	 *            is the Y coordinate of the first point of the first line.
+	 * @param z1
+	 *            is the Z coordinate of the first point of the first line.
+	 * @param x2
+	 *            is the X coordinate of the second point of the first line.
+	 * @param y2
+	 *            is the Y coordinate of the second point of the first line.
+	 * @param z2
+	 *            is the Z coordinate of the second point of the first line.
+	 * @param x3
+	 *            is the X coordinate of the first point of the second line.
+	 * @param y3
+	 *            is the Y coordinate of the first point of the second line.
+	 * @param z3
+	 *            is the Z coordinate of the first point of the second line.
+	 * @param x4
+	 *            is the X coordinate of the second point of the second line.
+	 * @param y4
+	 *            is the Y coordinate of the second point of the second line.
+	 * @param z4
+	 *            is the Z coordinate of the second point of the second line.
+	 * @return <code>true</code> if the two given lines are collinear.
+	 * @see #isParallelLines(float, float, float, float, float, float, float, float, float, float, float, float)
+	 * @see #isCollinearPoints(float, float, float, float, float, float, float, float, float)
+	 */
+	public static boolean isCollinearLines(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4) {
+		return (isParallelLines(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) && isCollinearPoints(x1, y1, z1, x2, y2, z2, x3, y3, z3));
+	}
+
+	/** Compute the zone where the point is against the given rectangle
+	 * according to the <a href="http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm";>Cohen-Sutherland algorithm</a>.
+	 * 
+	 * @param px is the coordinates of the points.
+	 * @param py is the coordinates of the points.
+	 * @param rxmin is the min of the coordinates of the rectangle.
+	 * @param rymin is the min of the coordinates of the rectangle.
+	 * @param rxmax is the max of the coordinates of the rectangle.
+	 * @param rymax is the max of the coordinates of the rectangle.
+	 * @return the zone
+	 */
+	public static int getCohenSutherlandCode(int px, int py, int rxmin, int rymin, int rxmax, int rymax) {
+		assert(rxmin<=rxmax);
+		assert(rymin<=rymax);
+		// initialised as being inside of clip window
+		int code = COHEN_SUTHERLAND_INSIDE;
+		if (px<rxmin) {
+			// to the left of clip window
+			code |= COHEN_SUTHERLAND_LEFT;
+		}
+		if (px>rxmax) {
+			// to the right of clip window
+			code |= COHEN_SUTHERLAND_RIGHT;
+		}
+		if (py<rymin) {
+			// to the bottom of clip window
+			code |= COHEN_SUTHERLAND_BOTTOM;
+		}
+		if (py>rymax) {
+			// to the top of clip window
+			code |= COHEN_SUTHERLAND_TOP;
+		}
+		return code;
+	}
+
+	/** Compute the zone where the point is against the given rectangle
+	 * according to the <a href="http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm";>Cohen-Sutherland algorithm</a>.
+	 * 
+	 * @param px is the coordinates of the points.
+	 * @param py is the coordinates of the points.
+	 * @param rxmin is the min of the coordinates of the rectangle.
+	 * @param rymin is the min of the coordinates of the rectangle.
+	 * @param rxmax is the max of the coordinates of the rectangle.
+	 * @param rymax is the max of the coordinates of the rectangle.
+	 * @return the zone
+	 */
+	public static int getCohenSutherlandCode(float px, float py, float rxmin, float rymin, float rxmax, float rymax) {
+		assert(rxmin<=rxmax);
+		assert(rymin<=rymax);
+		// initialised as being inside of clip window
+		int code = COHEN_SUTHERLAND_INSIDE;
+		if (px<rxmin) {
+			// to the left of clip window
+			code |= COHEN_SUTHERLAND_LEFT;
+		}
+		if (px>rxmax) {
+			// to the right of clip window
+			code |= COHEN_SUTHERLAND_RIGHT;
+		}
+		if (py<rymin) {
+			// to the bottom of clip window
+			code |= COHEN_SUTHERLAND_BOTTOM;
+		}
+		if (py>rymax) {
+			// to the top of clip window
+			code |= COHEN_SUTHERLAND_TOP;
+		}
+		return code;
+	}
+
+	/** Clip the given segment against the clipping rectangle
+	 * according to the <a href="http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm";>Cohen-Sutherland algorithm</a>.
+	 * 
+	 * @param p1 is the first point of the segment.
+	 * @param p2 is the first point of the segment.
+	 * @param rxmin is the min of the coordinates of the rectangle.
+	 * @param rymin is the min of the coordinates of the rectangle.
+	 * @param rxmax is the max of the coordinates of the rectangle.
+	 * @param rymax is the max of the coordinates of the rectangle.
+	 * @return <code>true</code> if the segment has an intersection with the
+	 * rectangle and the segment was clipped; <code>false</code> if the segment
+	 * does not intersect the rectangle.
+	 */
+	public static boolean clipSegmentToRectangle(Point2D p1, Point2D p2, float rxmin, float rymin, float rxmax, float rymax) {
+		float x0 = p1.getX();
+		float y0 = p1.getY();
+		float x1 = p2.getX();
+		float y1 = p2.getY();
+		int code1 = getCohenSutherlandCode(x0, y0, rxmin, rymin, rxmax, rymax);
+		int code2 = getCohenSutherlandCode(x1, y1, rxmin, rymin, rxmax, rymax);
+		boolean accept = false;
+		boolean cont = true;
+		float x, y;
+		x = y = 0;
+		
+		while (cont) {
+			if ((code1 | code2)==0) {
+				// Bitwise OR is 0. Trivially accept and get out of loop
+				accept = true;
+				cont = false;
+			}
+			else if ((code1 & code2)!=0) {
+				// Bitwise AND is not 0. Trivially reject and get out of loop
+				cont = false;
+			}
+			else {
+				// failed both tests, so calculate the line segment to clip
+				// from an outside point to an intersection with clip edge
+
+				// At least one endpoint is outside the clip rectangle; pick it.
+				int code3 = code1!=0 ? code1 : code2;
+
+				// Now find the intersection point;
+				// use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
+				if ((code3 & COHEN_SUTHERLAND_TOP)!=0) {
+					// point is above the clip rectangle
+					x = x0 + (x1 - x0) * (rymax - y0) / (y1 - y0);
+					y = rymax;
+				}
+				else if ((code3 & COHEN_SUTHERLAND_BOTTOM)!=0) {
+					// point is below the clip rectangle
+					x = x0 + (x1 - x0) * (rymin - y0) / (y1 - y0);
+					y = rymin;
+				}
+				else if ((code3 & COHEN_SUTHERLAND_RIGHT)!=0) { 
+					// point is to the right of clip rectangle
+					y = y0 + (y1 - y0) * (rxmax - x0) / (x1 - x0);
+					x = rxmax;
+				}
+				else if ((code3 & COHEN_SUTHERLAND_LEFT)!=0) {
+					// point is to the left of clip rectangle
+					y = y0 + (y1 - y0) * (rxmin - x0) / (x1 - x0);
+					x = rxmin;
+				}
+				else {
+					code3 = 0;
+				}
+
+				if (code3!=0) {
+					// Now we move outside point to intersection point to clip
+					// and get ready for next pass.
+					if (code3 == code1) {
+						x0 = x;
+						y0 = y;
+						code1 = getCohenSutherlandCode(x0, y0, rxmin, rymin, rxmax, rymax);
+					}
+					else {
+						x1 = x;
+						y1 = y;
+						code2 = getCohenSutherlandCode(x1, y1, rxmin, rymin, rxmax, rymax);
+					}
+				}
+			}
+		}
+		if (accept) {
+			p1.set(x0, y0);
+			p2.set(x1, y1);
+		}
+		return accept;
+	}
+
+	/** Clip the given segment against the clipping rectangle
+	 * according to the <a href="http://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm";>Cohen-Sutherland algorithm</a>.
+	 * 
+	 * @param p1 is the first point of the segment.
+	 * @param p2 is the first point of the segment.
+	 * @param rxmin is the min of the coordinates of the rectangle.
+	 * @param rymin is the min of the coordinates of the rectangle.
+	 * @param rxmax is the max of the coordinates of the rectangle.
+	 * @param rymax is the max of the coordinates of the rectangle.
+	 * @return <code>true</code> if the segment has an intersection with the
+	 * rectangle and the segment was clipped; <code>false</code> if the segment
+	 * does not intersect the rectangle.
+	 */
+	public static boolean clipSegmentToRectangle(Point2D p1, Point2D p2, int rxmin, int rymin, int rxmax, int rymax) {
+		int x0 = p1.x();
+		int y0 = p1.y();
+		int x1 = p2.x();
+		int y1 = p2.y();
+		int code1 = getCohenSutherlandCode(x0, y0, rxmin, rymin, rxmax, rymax);
+		int code2 = getCohenSutherlandCode(x1, y1, rxmin, rymin, rxmax, rymax);
+		boolean accept = false;
+		boolean cont = true;
+		int x, y;
+		x = y = 0;
+
+		while (cont) {
+			if ((code1 | code2)==0) {
+				// Bitwise OR is 0. Trivially accept and get out of loop
+				accept = true;
+				cont = false;
+			}
+			else if ((code1 & code2)!=0) {
+				// Bitwise AND is not 0. Trivially reject and get out of loop
+				cont = false;
+			}
+			else {
+				// failed both tests, so calculate the line segment to clip
+				// from an outside point to an intersection with clip edge
+
+				// At least one endpoint is outside the clip rectangle; pick it.
+				int code3 = code1!=0 ? code1 : code2;
+
+				// Now find the intersection point;
+				// use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
+				if ((code3 & COHEN_SUTHERLAND_TOP)!=0) {
+					// point is above the clip rectangle
+					x = x0 + (x1 - x0) * (rymax - y0) / (y1 - y0);
+					y = rymax;
+				}
+				else if ((code3 & COHEN_SUTHERLAND_BOTTOM)!=0) {
+					// point is below the clip rectangle
+					x = x0 + (x1 - x0) * (rymin - y0) / (y1 - y0);
+					y = rymin;
+				}
+				else if ((code3 & COHEN_SUTHERLAND_RIGHT)!=0) { 
+					// point is to the right of clip rectangle
+					y = y0 + (y1 - y0) * (rxmax - x0) / (x1 - x0);
+					x = rxmax;
+				}
+				else if ((code3 & COHEN_SUTHERLAND_LEFT)!=0) {
+					// point is to the left of clip rectangle
+					y = y0 + (y1 - y0) * (rxmin - x0) / (x1 - x0);
+					x = rxmin;
+				}
+				else {
+					code3 = 0;
+				}
+
+				if (code3!=0) {
+					// Now we move outside point to intersection point to clip
+					// and get ready for next pass.
+					if (code3 == code1) {
+						x0 = x;
+						y0 = y;
+						code1 = getCohenSutherlandCode(x0, y0, rxmin, rymin, rxmax, rymax);
+					}
+					else {
+						x1 = x;
+						y1 = y;
+						code2 = getCohenSutherlandCode(x1, y1, rxmin, rymin, rxmax, rymax);
+					}
+				}
+			}
+		}
+		if (accept) {
+			p1.set(x0, y0);
+			p2.set(x1, y1);
+		}
+		return accept;
+	}
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/AbstractRectangularShape2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/AbstractRectangularShape2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/AbstractRectangularShape2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,332 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import org.arakhne.afc.math.generic.Point2D;
+
+
+
+/** Abstract implementation of 2D rectangular shapes.
+ * 
+ * @param <T> is the type of the shape implemented by the instance of this class.
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class AbstractRectangularShape2f<T extends AbstractRectangularShape2f<T>>
+extends AbstractShape2f<T> {
+
+	private static final long serialVersionUID = -2330319571109966087L;
+
+	/** Lowest x-coordinate covered by this rectangular shape. */
+	protected float minx = 0f;
+	/** Lowest y-coordinate covered by this rectangular shape. */
+	protected float miny = 0f;
+	/** Highest x-coordinate covered by this rectangular shape. */
+	protected float maxx = 0f;
+	/** Highest y-coordinate covered by this rectangular shape. */
+	protected float maxy = 0f;
+	
+	/**
+	 */
+	public AbstractRectangularShape2f() {
+		//
+	}
+	
+	/**
+	 * @param min is the min corner of the rectangle.
+	 * @param max is the max corner of the rectangle.
+	 */
+	public AbstractRectangularShape2f(Point2f min, Point2f max) {
+		setFromCorners(min.getX(), min.getY(), max.getX(), max.getY());
+	}
+	
+	/**
+	 * @param x
+	 * @param y
+	 * @param width
+	 * @param height
+	 */
+	public AbstractRectangularShape2f(float x, float y, float width, float height) {
+		setFromCorners(x, y, x+width, y+height);
+	}
+	
+	@Override
+	public void clear() {
+		this.minx = this.miny = this.maxx = this.maxy = 0f;
+	}
+	
+	/** Change the frame of the rectangle.
+	 * 
+	 * @param x
+	 * @param y
+	 * @param width
+	 * @param height
+	 */
+	public void set(float x, float y, float width, float height) {
+		setFromCorners(x, y, x+width, y+height);
+	}
+	
+	/** Change the frame of te rectangle.
+	 * 
+	 * @param min is the min corner of the rectangle.
+	 * @param max is the max corner of the rectangle.
+	 */
+	public void set(Point2f min, Point2f max) {
+		setFromCorners(min.getX(), min.getY(), max.getX(), max.getY());
+	}
+	
+	/** Change the frame of te rectangle.
+	 * 
+	 * @param r
+	 */
+	public void set(AbstractRectangularShape2f<?> r) {
+		setFromCorners(r.getMinX(), r.getMinY(), r.getMaxX(), r.getMaxY());
+	}
+
+	/** Change the width of the rectangle, not the min corner.
+	 * 
+	 * @param width
+	 */
+	public void setWidth(float width) {
+		this.maxx = this.minx + Math.max(0f, width);
+	}
+
+	/** Change the height of the rectangle, not the min corner.
+	 * 
+	 * @param height
+	 */
+	public void setHeight(float height) {
+		this.maxy = this.miny + Math.max(0f, height);
+	}
+
+	/** Change the frame of the rectangle.
+	 * 
+	 * @param p1 is the coordinate of the first corner.
+	 * @param p2 is the coordinate of the second corner.
+	 */
+	public void setFromCorners(Point2D p1, Point2D p2) {
+		setFromCorners(p1.getX(), p1.getY(), p2.getX(), p2.getY());
+	}
+
+	/** Change the frame of the rectangle.
+	 * 
+	 * @param x1 is the coordinate of the first corner.
+	 * @param y1 is the coordinate of the first corner.
+	 * @param x2 is the coordinate of the second corner.
+	 * @param y2 is the coordinate of the second corner.
+	 */
+	public void setFromCorners(float x1, float y1, float x2, float y2) {
+		if (x1<x2) {
+			this.minx = x1;
+			this.maxx = x2;
+		}
+		else {
+			this.minx = x2;
+			this.maxx = x1;
+		}
+		if (y1<y2) {
+			this.miny = y1;
+			this.maxy = y2;
+		}
+		else {
+			this.miny = y2;
+			this.maxy = y1;
+		}
+	}
+	
+	/**
+     * Sets the framing rectangle of this <code>Shape</code>
+     * based on the specified center point coordinates and corner point
+     * coordinates.  The framing rectangle is used by the subclasses of
+     * <code>RectangularShape</code> to define their geometry.
+     *
+     * @param centerX the X coordinate of the specified center point
+     * @param centerY the Y coordinate of the specified center point
+     * @param cornerX the X coordinate of the specified corner point
+     * @param cornerY the Y coordinate of the specified corner point
+     */
+	public void setFromCenter(float centerX, float centerY, float cornerX, float cornerY) {
+		float dx = centerX - cornerX;
+		float dy = centerY - cornerY;
+		setFromCorners(cornerX, cornerY, centerX + dx, centerY + dy);
+	}
+	
+	/** Replies the min X.
+	 * 
+	 * @return the min x.
+	 */
+	public float getMinX() {
+		return this.minx;
+	}
+
+	/** Set the min X.
+	 * 
+	 * @param x the min x.
+	 */
+	public void setMinX(float x) {
+		float o = this.maxx;
+		if (o<x) {
+			this.minx = o;
+			this.maxx = x;
+		}
+		else {
+			this.minx = x;
+		}
+	}
+
+	/** Replies the center x.
+	 * 
+	 * @return the center x.
+	 */
+	public float getCenterX() {
+		return (this.minx + this.maxx) / 2f;
+	}
+
+	/** Replies the max x.
+	 * 
+	 * @return the max x.
+	 */
+	public float getMaxX() {
+		return this.maxx;
+	}
+
+	/** Set the max X.
+	 * 
+	 * @param x the max x.
+	 */
+	public void setMaxX(float x) {
+		float o = this.minx;
+		if (o>x) {
+			this.maxx = o;
+			this.minx = x;
+		}
+		else {
+			this.maxx = x;
+		}
+	}
+
+	/** Replies the min y.
+	 * 
+	 * @return the min y.
+	 */
+	public float getMinY() {
+		return this.miny;
+	}
+
+	/** Set the min Y.
+	 * 
+	 * @param y the min y.
+	 */
+	public void setMinY(float y) {
+		float o = this.maxy;
+		if (o<y) {
+			this.miny = o;
+			this.maxy = y;
+		}
+		else {
+			this.miny = y;
+		}
+	}
+
+	/** Replies the center y.
+	 * 
+	 * @return the center y.
+	 */
+	public float getCenterY() {
+		return (this.miny + this.maxy) / 2f;
+	}
+
+	/** Replies the max y.
+	 * 
+	 * @return the max y.
+	 */
+	public float getMaxY() {
+		return this.maxy;
+	}
+	
+	/** Set the max Y.
+	 * 
+	 * @param y the max y.
+	 */
+	public void setMaxY(float y) {
+		float o = this.miny;
+		if (o>y) {
+			this.maxy = o;
+			this.miny = y;
+		}
+		else {
+			this.maxy = y;
+		}
+	}
+
+	/** Replies the width.
+	 * 
+	 * @return the width.
+	 */
+	public float getWidth() {
+		return this.maxx - this.minx;
+	}
+
+	/** Replies the height.
+	 * 
+	 * @return the height.
+	 */
+	public float getHeight() {
+		return this.maxy - this.miny;
+	}
+	
+	@Override
+	public void translate(float dx, float dy) {
+		this.minx += dx;
+		this.miny += dy;
+		this.maxx += dx;
+		this.maxy += dy;
+	}
+
+	/** Replies if this rectangular shape is empty.
+	 * The rectangular shape is empty when the
+	 * two corners are at the same location.
+	 * 
+	 * @return <code>true</code> if the rectangular shape is empty;
+	 * otherwise <code>false</code>.
+	 */
+	@Override
+	public boolean isEmpty() {
+		return this.minx==this.maxx && this.miny==this.maxy; 
+	}
+	
+	/** Inflate this rectangle with the given amounts.
+	 * 
+	 * @param left
+	 * @param top
+	 * @param right
+	 * @param bottom
+	 */
+	public void inflate(float left, float top, float right, float bottom) {
+		this.minx -= left;
+		this.miny -= top;
+		this.maxx += right;
+		this.maxy += bottom;
+	}
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/AbstractShape2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/AbstractShape2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/AbstractShape2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,111 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.matrix.Transform2D;
+
+
+
+/** Abstract implementation of shapes.
+ * 
+ * @param <T> is the type of the shape implemented by the instance of this class.
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class AbstractShape2f<T extends Shape2f> implements Shape2f {
+
+	private static final long serialVersionUID = -2724377801599470453L;
+
+	/**
+	 */
+	public AbstractShape2f() {
+		//
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@SuppressWarnings("unchecked")
+	@Override
+	public T clone()  {
+		try {
+			return (T)super.clone();
+		}
+		catch (CloneNotSupportedException e) {
+			throw new Error(e);
+		}
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Shape2f createTransformedShape(Transform2D transform) {
+		return new Path2f(getPathIterator(transform));
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public final PathIterator2f getPathIterator() {
+		return getPathIterator(null);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distance(Point2D p) {
+		return (float)Math.sqrt(distanceSquared(p));
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public final boolean contains(Point2D p) {
+		return contains(p.getX(), p.getY());
+	}
+
+	
+	/** {@inheritDoc}
+	 */
+    @Override
+    public abstract boolean equals(Object obj);
+    
+    /** Compute the bit representation of the floating-point value.
+     * 
+     * @param d
+     * @return the bit representation.
+     */
+    protected static int floatToIntBits(float d) {
+		// Check for +0 or -0
+		if (d == 0f) {
+			return 0;
+		}
+		return Float.floatToIntBits(d);
+	}
+    
+	/** {@inheritDoc}
+	 */
+    @Override
+    public abstract int hashCode();
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Circle2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Circle2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Circle2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,651 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import java.util.NoSuchElementException;
+
+import org.arakhne.afc.math.MathUtil;
+import org.arakhne.afc.math.generic.PathWindingRule;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.matrix.Transform2D;
+
+
+
+/** 2D circle with floating-point points.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class Circle2f extends AbstractShape2f<Circle2f> {
+
+	private static final long serialVersionUID = -5535463117356287850L;
+
+	/**
+	 * ArcIterator.btan(Math.PI/2)
+	 */
+	static final float CTRL_VAL = 0.5522847498307933f;
+
+	/**
+	 * ctrlpts contains the control points for a set of 4 cubic
+	 * bezier curves that approximate a circle of radius 0.5
+	 * centered at 0.5, 0.5
+	 */
+	static final float PCV = 0.5f + CTRL_VAL * 0.5f;
+	/**
+	 * ctrlpts contains the control points for a set of 4 cubic
+	 * bezier curves that approximate a circle of radius 0.5
+	 * centered at 0.5, 0.5
+	 */
+	static final float NCV = 0.5f - CTRL_VAL * 0.5f;
+	/**
+	 * ctrlpts contains the control points for a set of 4 cubic
+	 * bezier curves that approximate a circle of radius 0.5
+	 * centered at 0.5, 0.5
+	 */
+	static float CTRL_PTS[][] = {
+		{  1.0f,  PCV,  PCV,  1.0f,  0.5f,  1.0f },
+		{  NCV,  1.0f,  0.0f,  PCV,  0.0f,  0.5f },
+		{  0.0f,  NCV,  NCV,  0.0f,  0.5f,  0.0f },
+		{  PCV,  0.0f,  1.0f,  NCV,  1.0f,  0.5f }
+	};
+
+	/** Replies if a rectangle is inside in the circle.
+	 * 
+	 * @param cx is the center of the circle.
+	 * @param cy is the center of the circle.
+	 * @param radius is the radius of the circle.
+	 * @param rx is the lowest corner of the rectangle.
+	 * @param ry is the lowest corner of the rectangle.
+	 * @param rwidth is the width of the rectangle.
+	 * @param rheight is the height of the rectangle.
+	 * @return <code>true</code> if the given rectangle is inside the circle;
+	 * otherwise <code>false</code>.
+	 */
+	public static boolean containsCircleRectangle(float cx, float cy, float radius, float rx, float ry, float rwidth, float rheight) {
+		float rcx = (rx + rwidth/2f);
+		float rcy = (ry + rheight/2f);
+		float farX;
+		if (cx<=rcx) farX = rx + rwidth;
+		else farX = rx;
+		float farY;
+		if (cy<=rcy) farY = ry + rheight;
+		else farY = ry;
+		return MathUtil.isPointInCircle(farX, farY, cx, cy, radius);
+	}
+
+	/** Replies if two circles are intersecting.
+	 * 
+	 * @param x1 is the center of the first circle
+	 * @param y1 is the center of the first circle
+	 * @param radius1 is the radius of the first circle
+	 * @param x2 is the center of the second circle
+	 * @param y2 is the center of the second circle
+	 * @param radius2 is the radius of the second circle
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsCircleCircle(float x1, float y1, float radius1, float x2, float y2, float radius2) {
+		float r = radius1+radius2;
+		return MathUtil.distanceSquaredPointToPoint(x1, y1, x2, y2) < (r*r);
+	}
+
+	/** Replies if a circle and a rectangle are intersecting.
+	 * 
+	 * @param x1 is the center of the circle
+	 * @param y1 is the center of the circle
+	 * @param radius is the radius of the circle
+	 * @param x2 is the first corner of the rectangle.
+	 * @param y2 is the first corner of the rectangle.
+	 * @param x3 is the second corner of the rectangle.
+	 * @param y3 is the second corner of the rectangle.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsCircleRectangle(float x1, float y1, float radius, float x2, float y2, float x3, float y3) {
+		float dx;
+		if (x1<x2) {
+			dx = x2 - x1;
+		}
+		else if (x1>x3) {
+			dx = x1 - x3;
+		}
+		else {
+			dx = 0f;
+		}
+		float dy;
+		if (y1<y2) {
+			dy = y2 - y1;
+		}
+		else if (y1>y3) {
+			dy = y1 - y3;
+		}
+		else {
+			dy = 0f;
+		}
+		return (dx*dx+dy*dy) < (radius*radius);
+	}
+
+	/** Replies if a circle and a line are intersecting.
+	 * 
+	 * @param x1 is the center of the circle
+	 * @param y1 is the center of the circle
+	 * @param radius is the radius of the circle
+	 * @param x2 is the first point of the line.
+	 * @param y2 is the first point of the line.
+	 * @param x3 is the second point of the line.
+	 * @param y3 is the second point of the line.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsCircleLine(float x1, float y1, float radius, float x2, float y2, float x3, float y3) {
+		float d = MathUtil.distanceSquaredPointToLine(x1, y1, x2, y2, x3, y3);
+		return d<(radius*radius);
+	}
+
+	/** Replies if a circle and a segment are intersecting.
+	 * 
+	 * @param x1 is the center of the circle
+	 * @param y1 is the center of the circle
+	 * @param radius is the radius of the circle
+	 * @param x2 is the first point of the segment.
+	 * @param y2 is the first point of the segment.
+	 * @param x3 is the second point of the segment.
+	 * @param y3 is the second point of the segment.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsCircleSegment(float x1, float y1, float radius, float x2, float y2, float x3, float y3) {
+		float d = MathUtil.distanceSquaredPointToSegment(x1, y1, x2, y2, x3, y3);
+		return d<(radius*radius);
+	}
+
+	/** X-coordinate of the circle center. */
+	protected float cx = 0f;
+	/** Y-coordinate of the circle center. */
+	protected float cy = 0f;
+	/** Radius of the circle center (must be always positive). */
+	protected float radius = 0f;
+
+	/**
+	 */
+	public Circle2f() {
+		//
+	}
+
+	/**
+	 * @param center
+	 * @param radius
+	 */
+	public Circle2f(Point2D center, float radius) {
+		set(center, radius);
+	}
+
+	/**
+	 * @param x
+	 * @param y
+	 * @param radius
+	 */
+	public Circle2f(float x, float y, float radius) {
+		set(x, y, radius);
+	}
+	
+	@Override
+	public void clear() {
+		this.cx = this.cy = 0f;
+		this.radius = 0f;
+	}
+	
+	/** Replies if the circle is empty.
+	 * The circle is empty when the radius is nul.
+	 * 
+	 * @return <code>true</code> if the radius is nul;
+	 * otherwise <code>false</code>.
+	 */
+	@Override
+	public boolean isEmpty() {
+		return this.radius<=+0f;
+	}
+
+	/** Change the frame of the circle.
+	 * 
+	 * @param x
+	 * @param y
+	 * @param radius
+	 */
+	public void set(float x, float y, float radius) {
+		this.cx = x;
+		this.cy = y;
+		this.radius = Math.abs(radius);
+	}
+
+	/** Change the frame of te circle.
+	 * 
+	 * @param center
+	 * @param radius
+	 */
+	public void set(Point2D center, float radius) {
+		this.cx = center.getX();
+		this.cy = center.getY();
+		this.radius = Math.abs(radius);
+	}
+
+	/** Replies the center X.
+	 * 
+	 * @return the center x.
+	 */
+	public float getX() {
+		return this.cx;
+	}
+
+	/** Replies the center y.
+	 * 
+	 * @return the center y.
+	 */
+	public float getY() {
+		return this.cy;
+	}
+
+	/** Replies the center.
+	 * 
+	 * @return a copy of the center.
+	 */
+	public Point2f getCenter() {
+		return new Point2f(this.cx, this.cy);
+	}
+
+	/** Replies the center.
+	 * 
+	 * @param center
+	 */
+	public void setCenter(Point2D center) {
+		this.cx = center.getX();
+		this.cy = center.getY();
+	}
+
+	/** Replies the center.
+	 * 
+	 * @param x
+	 * @param y
+	 */
+	public void setCenter(float x, float y) {
+		this.cx = x;
+		this.cy = y;
+	}
+
+	/** Replies the radius.
+	 * 
+	 * @return the radius.
+	 */
+	public float getRadius() {
+		return this.radius;
+	}
+
+	/** Set the radius.
+	 * 
+	 * @param radius is the radius.
+	 */
+	public void setRadius(float radius) {
+		this.radius = Math.abs(radius);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Rectangle2f toBoundingBox() {
+		Rectangle2f r = new Rectangle2f();
+		r.setFromCorners(
+				this.cx-this.radius,
+				this.cy-this.radius,
+				this.cx+this.radius,
+				this.cy+this.radius);
+		return r;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distance(Point2D p) {
+		float d = MathUtil.distancePointToPoint(getX(), getY(), p.getX(), p.getY()) - getRadius();
+		return Math.max(0f, d);
+	}
+	
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceSquared(Point2D p) {
+		float d = distance(p);
+		return d * d;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceL1(Point2D p) {
+		Point2D r = getClosestPointTo(p);
+		return r.distanceL1(p);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceLinf(Point2D p) {
+		Point2D r = getClosestPointTo(p);
+		return r.distanceLinf(p);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean contains(float x, float y) {
+		return MathUtil.isPointInCircle(x, y, getX(), getY(), getRadius());
+	}
+	
+	@Override
+	public boolean contains(Rectangle2f r) {
+		return containsCircleRectangle(getX(), getY(), getRadius(),
+				r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight());
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Point2f getClosestPointTo(Point2D p) {
+		Vector2f v = new Vector2f(p);
+		v.sub(this.cx, this.cy);
+		float l = v.lengthSquared();
+		if (l<=(this.radius*this.radius)) {
+			if (p instanceof Point2f) return (Point2f)p;
+			return new Point2f(p);
+		}
+		float s = this.radius/(float)Math.sqrt(l);
+		v.scale(s);
+		return new Point2f(this.cx + v.getX(), this.cy + v.getY());
+	}
+
+	@Override
+	public void translate(float dx, float dy) {
+		this.cx += dx;
+		this.cy += dy;
+	}
+	
+	@Override
+	public PathIterator2f getPathIterator(Transform2D transform) {
+		if (transform==null)
+			return new CopyPathIterator(getX(), getY(), getRadius());
+		return new TransformPathIterator(getX(), getY(), getRadius(), transform);
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (obj instanceof Circle2f) {
+			Circle2f rr2d = (Circle2f) obj;
+			return ((getX() == rr2d.getX()) &&
+					(getY() == rr2d.getY()) &&
+					(getRadius() == rr2d.getRadius()));
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		long bits = 1L;
+		bits = 31L * bits + floatToIntBits(getX());
+		bits = 31L * bits + floatToIntBits(getY());
+		bits = 31L * bits + floatToIntBits(getRadius());
+		return (int) (bits ^ (bits >> 32));
+	}
+
+	@Override
+	public boolean intersects(Rectangle2f s) {
+		return intersectsCircleRectangle(
+				getX(), getY(), getRadius(),
+				s.getMinX(), s.getMinY(),
+				s.getMaxX(), s.getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Ellipse2f s) {
+		return Ellipse2f.intersectsEllipseEllipse(
+				getX()-getRadius(), getY()-getRadius(),
+				getX()+getRadius(), getY()+getRadius(),
+				s.getMinX(), s.getMinY(),
+				s.getMaxX(), s.getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Circle2f s) {
+		return intersectsCircleCircle(
+				getX(), getY(), getRadius(),
+				s.getX(), s.getY(), s.getRadius());
+	}
+
+	@Override
+	public boolean intersects(Segment2f s) {
+		return intersectsCircleSegment(
+				getX(), getY(), getRadius(),
+				s.getX1(), s.getY1(),
+				s.getX2(), s.getY2());
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append("["); //$NON-NLS-1$
+		b.append(getX());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getY());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getRadius());
+		b.append("]"); //$NON-NLS-1$
+		return b.toString();
+	}
+
+	/** Iterator on the path elements of the circle.
+	 * 
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private static class CopyPathIterator implements PathIterator2f {
+		
+		private final float x;
+		private final float y;
+		private final float r;
+		private int index = 0;
+		private float movex, movey;
+		private float lastx, lasty;
+		
+		/**
+		 * @param x
+		 * @param y
+		 * @param r
+		 */
+		public CopyPathIterator(float x, float y, float r) {
+			this.r = Math.max(0f, r);
+			this.x = x - this.r;
+			this.y = y - this.r;
+			if (this.r<=0f) {
+				this.index = 6;
+			}
+		}
+	
+		@Override
+		public boolean hasNext() {
+			return this.index<=5;
+		}
+	
+		@Override
+		public PathElement2f next() {
+			if (this.index>5) throw new NoSuchElementException();
+			int idx = this.index;
+			++this.index;
+			if (idx==0) {
+				float dr = 2f * this.r;
+				float ctrls[] = CTRL_PTS[3];
+				this.movex = (this.x + ctrls[4] * dr);
+				this.movey = (this.y + ctrls[5] * dr);
+				this.lastx = this.movex;
+				this.lasty = this.movey;
+				return new PathElement2f.MovePathElement2f(
+						this.lastx, this.lasty);
+			}
+			else if (idx<5) {
+				float dr = 2f * this.r;
+				float ctrls[] = CTRL_PTS[idx - 1];
+				float ppx = this.lastx;
+				float ppy = this.lasty;
+				this.lastx = (this.x + ctrls[4] * dr);
+				this.lasty = (this.y + ctrls[5] * dr);
+				return new PathElement2f.CurvePathElement2f(
+						ppx, ppy,
+						(this.x + ctrls[0] * dr),
+						(this.y + ctrls[1] * dr),
+						(this.x + ctrls[2] * dr),
+						(this.y + ctrls[3] * dr),
+						this.lastx, this.lasty);
+			}
+			float ppx = this.lastx;
+			float ppy = this.lasty;
+			this.lastx = this.movex;
+			this.lasty = this.movey;
+			return new PathElement2f.ClosePathElement2f(
+					ppx, ppy,
+					this.lastx, this.lasty);
+		}
+	
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+	
+		@Override
+		public PathWindingRule getWindingRule() {
+			return PathWindingRule.NON_ZERO;
+		}
+		
+	}
+	
+	/** Iterator on the path elements of the circle.
+	 * 
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private static class TransformPathIterator implements PathIterator2f {
+			
+		private final Point2D p1 = new Point2f();
+		private final Point2D p2 = new Point2f();
+		private final Point2D ptmp1 = new Point2f();
+		private final Point2D ptmp2 = new Point2f();
+		private final Transform2D transform;
+		private final float x;
+		private final float y;
+		private final float r;
+		private int index = 0;
+		private float movex, movey;
+		
+		/**
+		 * @param x
+		 * @param y
+		 * @param r
+		 * @param transform
+		 */
+		public TransformPathIterator(float x, float y, float r, Transform2D transform) {
+			assert(transform!=null);
+			this.transform = transform;
+			this.r = Math.max(0f, r);
+			this.x = x - this.r;
+			this.y = y - this.r;
+			if (this.r<=0f) {
+				this.index = 6;
+			}
+		}
+	
+		@Override
+		public boolean hasNext() {
+			return this.index<=5;
+		}
+	
+		@Override
+		public PathElement2f next() {
+			if (this.index>5) throw new NoSuchElementException();
+			int idx = this.index;
+			++this.index;
+			if (idx==0) {
+				float dr = 2f * this.r;
+				float ctrls[] = CTRL_PTS[3];
+				this.movex = (this.x + ctrls[4] * dr);
+				this.movey = (this.y + ctrls[5] * dr);
+				this.p2.set(this.movex, this.movey);
+				this.transform.transform(this.p2);
+				return new PathElement2f.MovePathElement2f(
+						this.p2.getX(), this.p2.getY());
+			}
+			else if (idx<5) {
+				float dr = 2f * this.r;
+				float ctrls[] = CTRL_PTS[idx - 1];
+				this.p1.set(this.p2);
+				this.p2.set(
+						(this.x + ctrls[4] * dr),
+						(this.y + ctrls[5] * dr));
+				this.transform.transform(this.p2);
+				this.ptmp1.set(
+						(this.x + ctrls[0] * dr),
+						(this.y + ctrls[1] * dr));
+				this.transform.transform(this.ptmp1);
+				this.ptmp2.set(
+						(this.x + ctrls[2] * dr),
+						(this.y + ctrls[3] * dr));
+				this.transform.transform(this.ptmp2);
+				return new PathElement2f.CurvePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.ptmp1.getX(), this.ptmp1.getY(),
+						this.ptmp2.getX(), this.ptmp2.getY(),
+						this.p2.getX(), this.p2.getY());
+			}
+			this.p1.set(this.p2);
+			this.p2.set(this.movex, this.movey);
+			this.transform.transform(this.p2);
+			return new PathElement2f.ClosePathElement2f(
+					this.p1.getX(), this.p1.getY(),
+					this.p2.getX(), this.p2.getY());
+		}
+	
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+	
+		@Override
+		public PathWindingRule getWindingRule() {
+			return PathWindingRule.NON_ZERO;
+		}
+		
+	}
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Ellipse2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Ellipse2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Ellipse2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,699 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import java.util.NoSuchElementException;
+
+import org.arakhne.afc.math.MathUtil;
+import org.arakhne.afc.math.generic.PathWindingRule;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.matrix.Transform2D;
+
+
+/** 2D ellipse with floating-point points.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class Ellipse2f extends AbstractRectangularShape2f<Ellipse2f> {
+
+	private static final long serialVersionUID = -2745313055404516167L;
+
+	// ArcIterator.btan(Math.PI/2)
+	private static final float CTRL_VAL = 0.5522847498307933f;
+
+	/**
+	 * ctrlpts contains the control points for a set of 4 cubic
+	 * bezier curves that approximate a circle of radius 0.5
+	 * centered at 0.5, 0.5
+	 */
+	static final float PCV = 0.5f + CTRL_VAL * 0.5f;
+	/**
+	 * ctrlpts contains the control points for a set of 4 cubic
+	 * bezier curves that approximate a circle of radius 0.5
+	 * centered at 0.5, 0.5
+	 */
+	static final float NCV = 0.5f - CTRL_VAL * 0.5f;
+	/**
+	 * ctrlpts contains the control points for a set of 4 cubic
+	 * bezier curves that approximate a circle of radius 0.5
+	 * centered at 0.5, 0.5
+	 */
+	static final float CTRL_PTS[][] = {
+		{  1.0f,  PCV,  PCV,  1.0f,  0.5f,  1.0f },
+		{  NCV,  1.0f,  0.0f,  PCV,  0.0f,  0.5f },
+		{  0.0f,  NCV,  NCV,  0.0f,  0.5f,  0.0f },
+		{  PCV,  0.0f,  1.0f,  NCV,  1.0f,  0.5f }
+	};
+
+	/** Replies if a rectangle is inside in the ellipse.
+	 * 
+	 * @param ex is the lowest corner of the ellipse.
+	 * @param ey is the lowest corner of the ellipse.
+	 * @param ewidth is the width of the ellipse.
+	 * @param eheight is the height of the ellipse.
+	 * @param rx is the lowest corner of the rectangle.
+	 * @param ry is the lowest corner of the rectangle.
+	 * @param rwidth is the width of the rectangle.
+	 * @param rheight is the height of the rectangle.
+	 * @return <code>true</code> if the given rectangle is inside the ellipse;
+	 * otherwise <code>false</code>.
+	 */
+	public static boolean containsEllipseRectangle(float ex, float ey, float ewidth, float eheight, float rx, float ry, float rwidth, float rheight) {
+		float ecx = (ex + ewidth/2f);
+		float ecy = (ey + eheight/2f);
+		float rcx = (rx + rwidth/2f);
+		float rcy = (ry + rheight/2f);
+		float farX;
+		if (ecx<=rcx) farX = rx + rwidth;
+		else farX = rx;
+		float farY;
+		if (ecy<=rcy) farY = ry + rheight;
+		else farY = ry;
+		return MathUtil.isPointInEllipse(farX, farY, ex, ey, ewidth, eheight);
+	}
+
+	/** Replies if two ellipses are intersecting.
+	 * 
+	 * @param x1 is the first corner of the first ellipse.
+	 * @param y1 is the first corner of the first ellipse.
+	 * @param x2 is the second corner of the first ellipse.
+	 * @param y2 is the second corner of the first ellipse.
+	 * @param x3 is the first corner of the second ellipse.
+	 * @param y3 is the first corner of the second ellipse.
+	 * @param x4 is the second corner of the second ellipse.
+	 * @param y4 is the second corner of the second ellipse.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsEllipseEllipse(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		float ell2w = Math.abs(x4 - x3);
+		float ell2h = Math.abs(y4 - y3);
+		float ellw = Math.abs(x2 - x1);
+		float ellh = Math.abs(y2 - y1);
+
+		if (ell2w <= 0f || ell2h <= 0f) return false;
+		if (ellw <= 0f || ellh <= 0f) return false;
+
+		// Normalize the second ellipse coordinates compared to the ellipse
+		// having a center at 0,0 and a radius of 0.5.
+		float normx0 = (x3 - x1) / ellw - 0.5f;
+		float normx1 = normx0 + ell2w / ellw;
+		float normy0 = (y3 - y1) / ellh - 0.5f;
+		float normy1 = normy0 + ell2h / ellh;
+
+		// find nearest x (left edge, right edge, 0.0)
+		// find nearest y (top edge, bottom edge, 0.0)
+		// if nearest x,y is inside circle of radius 0.5, then intersects
+		float nearx, neary;
+		if (normx0 > 0f) {
+			// center to left of X extents
+			nearx = normx0;
+		} else if (normx1 < 0f) {
+			// center to right of X extents
+			nearx = normx1;
+		} else {
+			nearx = 0f;
+		}
+		if (normy0 > 0f) {
+			// center above Y extents
+			neary = normy0;
+		} else if (normy1 < 0f) {
+			// center below Y extents
+			neary = normy1;
+		} else {
+			neary = 0f;
+		}
+		return (nearx * nearx + neary * neary) < 0.25f;
+	}
+
+	/** Replies if an ellipse and a line are intersecting.
+	 * 
+	 * @param x1 is the first corner of the ellipse.
+	 * @param y1 is the first corner of the ellipse.
+	 * @param x2 is the second corner of the ellipse.
+	 * @param y2 is the second corner of the ellipse.
+	 * @param x3 is the first point of the line.
+	 * @param y3 is the first point of the line.
+	 * @param x4 is the second point of the line.
+	 * @param y4 is the second point of the line.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsEllipseLine(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		float a = (x2 - x1) / 2f;
+		float b = (y2 - y1) / 2f;
+		float h = x1 + a; // h is center of ellipse
+		float k = y1 + b; // k is center of ellipse
+
+		float aas = a*a;
+		float bbs = b*b;
+
+		float aa, bb, cc;
+
+		if (x3!=x4) {
+			float m = (y4-y3)/(x4-x3);
+			float c = y3 - m*x3;
+			//
+			aa = bbs + aas*m*m;
+			bb = 2*aas*c*m - 2*aas*k*m - 2*h*bbs;
+			cc = bbs*h*h + aas*c*c - 2*aas*k*c + aas*k*k - aas*bbs;
+		}
+		else {
+			//
+			// vertical line case
+			//
+			aa = aas;
+			bb = -2f*k*aas;
+			cc = -aas*bbs + bbs*(x3-h)*(x3-h);
+		}
+
+		float d = bb*bb-4*aa*cc;
+		return (d > 0f);
+	}
+
+	/** Replies if an ellipse and a segment are intersecting.
+	 * 
+	 * @param x1 is the first corner of the ellipse.
+	 * @param y1 is the first corner of the ellipse.
+	 * @param x2 is the second corner of the ellipse.
+	 * @param y2 is the second corner of the ellipse.
+	 * @param x3 is the first point of the segment.
+	 * @param y3 is the first point of the segment.
+	 * @param x4 is the second point of the segment.
+	 * @param y4 is the second point of the segment.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsEllipseSegment(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		if (x1==x2 || y1==y2) return false;
+		
+		float a = (x2 - x1) / 2f;
+		float b = (y2 - y1) / 2f;
+		float h = x1 + a; // h is center of ellipse
+		float k = y1 + b; // k is center of ellipse
+
+		float aas = a*a;
+		float bbs = b*b;
+
+		float aa, bb, cc;
+		
+		float m = Float.NaN;
+
+		if (x3!=x4) {
+			m = (y4-y3)/(x4-x3);
+			float c = y3 - m*x3;
+			//
+			aa = bbs + aas*m*m;
+			bb = 2*aas*c*m - 2*aas*k*m - 2*h*bbs;
+			cc = bbs*h*h + aas*c*c - 2*aas*k*c + aas*k*k - aas*bbs;
+		}
+		else {
+			//
+			// vertical line case
+			//
+			aa = aas;
+			bb = -2f*k*aas;
+			cc = -aas*bbs + bbs*(x3-h)*(x3-h);
+		}
+
+		float d = bb*bb-4*aa*cc;
+		if (d > 0f) {
+			// Intersection exists between the ellipse and the line.
+			float rootd = (float)Math.sqrt(d);
+			float aa2 = aa*2f;
+
+			float root1 = (-bb + rootd) / aa2;
+			float root2 = (-bb - rootd) / aa2;
+			
+			// Intersection points are (xi1;yi1) and (xi2;yi2)
+			float xi1, xi2, yi1, yi2;
+			
+			if (Float.isNaN(m)) {
+				// Vertical line
+				xi1 = xi2 = x1;
+				yi1 = root1;
+				yi2 = root2;
+			}
+			else {
+				xi1 = root1;
+				xi2 = root2;
+				yi1 = y1 + m * (xi1 - x1);
+				yi2 = y1 + m * (xi2 - x1);
+			}
+			
+			// Compute the relative position of the roots again the segment coordinates
+			// Reuse aa and bb as temp vars.
+			// Reuse d as the length of the segment.
+			// Reuse a and b as the length of the two roots.
+			aa = x4 - x3;
+			bb = y4 - y3;
+			d = aa*aa + bb*bb;
+			aa = xi1 - x3;
+			bb = yi1 - y3;
+			a = aa*aa + bb*bb;
+			aa = xi2 - x3;
+			bb = yi2 - y3;
+			b = aa*aa + bb*bb;
+			
+			if (b<a) {
+				// Ensure root1 and root2 are ordered
+				aa = a;
+				a = b;
+				b = aa;
+			}
+			
+			// Test intersection of 1D segments [a;b] and [0;d]
+			// No intersection when: ( b<=0f ) || ( a>=d )
+			return ( b>0f ) && ( a<d );
+		}
+		return false;
+	}
+
+	/** Replies if two ellipses are intersecting.
+	 * 
+	 * @param x1 is the first corner of the first ellipse.
+	 * @param y1 is the first corner of the first ellipse.
+	 * @param x2 is the second corner of the first ellipse.
+	 * @param y2 is the second corner of the first ellipse.
+	 * @param x3 is the first corner of the second rectangle.
+	 * @param y3 is the first corner of the second rectangle.
+	 * @param x4 is the second corner of the second rectangle.
+	 * @param y4 is the second corner of the second rectangle.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsEllipseRectangle(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		// From AWT Ellipse2D
+
+		float rectw = Math.abs(x4 - x3);
+		float recth = Math.abs(y4 - y3);
+		float ellw = Math.abs(x2 - x1);
+		float ellh = Math.abs(y2 - y1);
+
+		if (rectw <= 0f || recth <= 0f) return false;
+		if (ellw <= 0f || ellh <= 0f) return false;
+
+		// Normalize the rectangular coordinates compared to the ellipse
+		// having a center at 0,0 and a radius of 0.5.
+		float normx0 = (x3 - x1) / ellw - 0.5f;
+		float normx1 = normx0 + rectw / ellw;
+		float normy0 = (y3 - y1) / ellh - 0.5f;
+		float normy1 = normy0 + recth / ellh;
+		// find nearest x (left edge, right edge, 0.0)
+		// find nearest y (top edge, bottom edge, 0.0)
+		// if nearest x,y is inside circle of radius 0.5, then intersects
+		float nearx, neary;
+		if (normx0 > 0f) {
+			// center to left of X extents
+			nearx = normx0;
+		} else if (normx1 < 0f) {
+			// center to right of X extents
+			nearx = normx1;
+		} else {
+			nearx = 0f;
+		}
+		if (normy0 > 0f) {
+			// center above Y extents
+			neary = normy0;
+		} else if (normy1 < 0f) {
+			// center below Y extents
+			neary = normy1;
+		} else {
+			neary = 0f;
+		}
+		return (nearx * nearx + neary * neary) < 0.25f;
+	}
+
+	/**
+	 */
+	public Ellipse2f() {
+		//
+	}
+
+	/**
+	 * @param min is the min corner of the ellipse.
+	 * @param max is the max corner of the ellipse.
+	 */
+	public Ellipse2f(Point2f min, Point2f max) {
+		super(min, max);
+	}
+
+	/**
+	 * @param x
+	 * @param y
+	 * @param width
+	 * @param height
+	 */
+	public Ellipse2f(float x, float y, float width, float height) {
+		super(x, y, width, height);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Rectangle2f toBoundingBox() {
+		return new Rectangle2f(getMinX(), getMinY(), getMaxX(), getMaxY());
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceSquared(Point2D p) {
+		Point2D r = getClosestPointTo(p);
+		return r.distanceSquared(p);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceL1(Point2D p) {
+		Point2D r = getClosestPointTo(p);
+		return r.distanceL1(p);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceLinf(Point2D p) {
+		Point2D r = getClosestPointTo(p);
+		return r.distanceLinf(p);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean contains(float x, float y) {
+		return MathUtil.isPointInEllipse(
+				x, y,
+				getMinX(), getMinY(), getWidth(), getHeight());
+	}
+	
+	@Override
+	public boolean contains(Rectangle2f r) {
+		return containsEllipseRectangle(
+				getMinX(), getMinY(), getWidth(), getHeight(),
+				r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight());
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Point2D getClosestPointTo(Point2D p) {
+		return MathUtil.getClosestPointToSolidEllipse(
+				p.getX(), p.getY(),
+				getMinX(), getMinY(),
+				getWidth(), getHeight());
+	}
+	
+	@Override
+	public PathIterator2f getPathIterator(Transform2D transform) {
+		if (transform==null) {
+			return new CopyPathIterator(
+					getMinX(), getMinY(),
+					getMaxX(), getMaxY());
+		}
+		return new TransformPathIterator(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				transform);
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (obj instanceof Ellipse2f) {
+			Ellipse2f rr2d = (Ellipse2f) obj;
+			return ((getMinX() == rr2d.getMinX()) &&
+					(getMinY() == rr2d.getMinY()) &&
+					(getWidth() == rr2d.getWidth()) &&
+					(getHeight() == rr2d.getHeight()));
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		long bits = 1L;
+		bits = 31L * bits + floatToIntBits(getMinX());
+		bits = 31L * bits + floatToIntBits(getMinY());
+		bits = 31L * bits + floatToIntBits(getMaxX());
+		bits = 31L * bits + floatToIntBits(getMaxY());
+		return (int) (bits ^ (bits >> 32));
+	}
+
+	@Override
+	public boolean intersects(Rectangle2f s) {
+		return intersectsEllipseRectangle(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				s.getMinX(), s.getMinY(),
+				s.getMaxX(), s.getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Ellipse2f s) {
+		return intersectsEllipseRectangle(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				s.getMinX(), s.getMinY(),
+				s.getMaxX(), s.getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Circle2f s) {
+		return intersectsEllipseEllipse(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				s.getX()-s.getRadius(), s.getY()-s.getRadius(),
+				s.getX()+s.getRadius(), s.getY()+s.getRadius());
+	}
+
+	@Override
+	public boolean intersects(Segment2f s) {
+		return intersectsEllipseSegment(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				s.getX1(), s.getY1(),
+				s.getX2(), s.getY2());
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append("["); //$NON-NLS-1$
+		b.append(getMinX());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMinY());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMaxX());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMaxY());
+		b.append("]"); //$NON-NLS-1$
+		return b.toString();
+	}
+
+	/**
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public static class CopyPathIterator implements PathIterator2f {
+		
+		private final float x1;
+		private final float y1;
+		private final float w;
+		private final float h;
+		private int index;
+		private float lastX, lastY;
+		
+		/**
+		 * @param x1
+		 * @param y1
+		 * @param x2
+		 * @param y2
+		 */
+		public CopyPathIterator(float x1, float y1, float x2, float y2) {
+			this.x1 = x1;
+			this.y1 = y1;
+			this.w = x2 - x1;
+			this.h = y2 - y1;
+			if (this.w==0f && this.h==0f) {
+				this.index = 6;
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.index<=5;
+		}
+
+		@Override
+		public PathElement2f next() {
+			if (this.index>5) throw new NoSuchElementException();
+			int idx = this.index;
+			++this.index;
+			
+			if (idx==0) {
+				float ctrls[] = CTRL_PTS[3];
+				this.lastX = this.x1 + ctrls[4] * this.w;
+				this.lastY = this.y1 + ctrls[5] * this.h;
+				return new PathElement2f.MovePathElement2f(
+						this.lastX,  this.lastY);
+			}
+			else if (idx<5) {
+				float ctrls[] = CTRL_PTS[idx - 1];
+				float ix = this.lastX;
+				float iy = this.lastY;
+				this.lastX = (this.x1 + ctrls[4] * this.w);
+				this.lastY = (this.y1 + ctrls[5] * this.h);
+				return new PathElement2f.CurvePathElement2f(
+						ix,  iy,
+						(this.x1 + ctrls[0] * this.w),
+						(this.y1 + ctrls[1] * this.h),
+						(this.x1 + ctrls[2] * this.w),
+						(this.y1 + ctrls[3] * this.h),
+						this.lastX,
+						this.lastY);
+			}
+
+			return new PathElement2f.ClosePathElement2f(
+					this.lastX, this.lastY,
+					this.lastX, this.lastY);
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return PathWindingRule.NON_ZERO;
+		}
+		
+	}
+
+	/**
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public static class TransformPathIterator implements PathIterator2f {
+		
+		private final Point2D lastPoint = new Point2f();
+		private final Point2D ptmp1 = new Point2f();
+		private final Point2D ptmp2 = new Point2f();
+		private final Transform2D transform;
+		private final float x1;
+		private final float y1;
+		private final float w;
+		private final float h;
+		private int index;
+		
+		/**
+		 * @param x1
+		 * @param y1
+		 * @param x2
+		 * @param y2
+		 * @param transform
+		 */
+		public TransformPathIterator(float x1, float y1, float x2, float y2, Transform2D transform) {
+			this.transform = transform;
+			this.x1 = x1;
+			this.y1 = y1;
+			this.w = x2 - x1;
+			this.h = y2 - y1;
+			if (this.w==0f && this.h==0f) {
+				this.index = 6;
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.index<=5;
+		}
+
+		@Override
+		public PathElement2f next() {
+			if (this.index>5) throw new NoSuchElementException();
+			int idx = this.index;
+			++this.index;
+			
+			if (idx==0) {
+				float ctrls[] = CTRL_PTS[3];
+				this.lastPoint.set(
+						this.x1 + ctrls[4] * this.w,
+						this.y1 + ctrls[5] * this.h);
+				this.transform.transform(this.lastPoint);
+				return new PathElement2f.MovePathElement2f(
+						this.lastPoint.getX(), this.lastPoint.getY());
+			}
+			else if (idx<5) {
+				float ctrls[] = CTRL_PTS[idx - 1];
+				float ix = this.lastPoint.getX();
+				float iy = this.lastPoint.getY();
+				this.lastPoint.set(
+						(this.x1 + ctrls[4] * this.w),
+						(this.y1 + ctrls[5] * this.h));
+				this.transform.transform(this.lastPoint);
+				this.ptmp1.set(
+						(this.x1 + ctrls[0] * this.w),
+						(this.y1 + ctrls[1] * this.h));
+				this.transform.transform(this.ptmp1);
+				this.ptmp2.set(
+						(this.x1 + ctrls[2] * this.w),
+						(this.y1 + ctrls[3] * this.h));
+				this.transform.transform(this.ptmp2);
+				return new PathElement2f.CurvePathElement2f(
+						ix,  iy,
+						this.ptmp1.getX(), this.ptmp1.getY(),
+						this.ptmp2.getX(), this.ptmp2.getY(),
+						this.lastPoint.getX(), this.lastPoint.getY());
+			}
+
+			float ix = this.lastPoint.getX();
+			float iy = this.lastPoint.getY();
+			return new PathElement2f.ClosePathElement2f(
+					ix, iy,
+					ix, iy);
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return PathWindingRule.NON_ZERO;
+		}
+		
+	}
+	
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Path2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Path2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Path2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,2866 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2005-09 Stephane GALLAND.
+ * Copyright (C) 2012-13 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import java.lang.ref.SoftReference;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.arakhne.afc.math.MathConstants;
+import org.arakhne.afc.math.MathUtil;
+import org.arakhne.afc.math.generic.PathElementType;
+import org.arakhne.afc.math.generic.PathWindingRule;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.matrix.Transform2D;
+
+
+/** A generic path.
+ *
+ * @author $Author: galland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class Path2f extends AbstractShape2f<Path2f> {
+
+	private static final long serialVersionUID = -873231223923726975L;
+
+	/** Multiple of cubic & quad curve size.
+	 */
+	static final int GROW_SIZE = 24;
+
+	/**
+	 * Tests if the specified coordinates are inside the closed
+	 * boundary of the specified {@link PathIterator2f}.
+	 * <p>
+	 * This method provides a basic facility for implementors of
+	 * the {@link Shape2f} interface to implement support for the
+	 * {@link Shape2f#contains(float, float)} method.
+	 *
+	 * @param pi the specified {@code PathIterator2f}
+	 * @param x the specified X coordinate
+	 * @param y the specified Y coordinate
+	 * @return {@code true} if the specified coordinates are inside the
+	 *         specified {@code PathIterator2f}; {@code false} otherwise
+	 */
+	public static boolean contains(PathIterator2f pi, float x, float y) {
+		// Copied from the AWT API
+		int mask = (pi.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 1);
+		int cross = computeCrossingsFromPoint(pi, x, y);
+		return ((cross & mask) != 0);
+	}
+
+	/**
+	 * Tests if the specified rectangle is inside the closed
+	 * boundary of the specified {@link PathIterator2f}.
+	 * <p>
+	 * This method provides a basic facility for implementors of
+	 * the {@link Shape2f} interface to implement support for the
+	 * {@link Shape2f#contains(Rectangle2f)} method.
+	 *
+	 * @param pi the specified {@code PathIterator2f}
+	 * @param rx the lowest corner of the rectangle.
+	 * @param ry the lowest corner of the rectangle.
+	 * @param rwidth is the width of the rectangle.
+	 * @param rheight is the width of the rectangle.
+	 * @return {@code true} if the specified rectangle is inside the
+	 *         specified {@code PathIterator2f}; {@code false} otherwise.
+	 */
+	public static boolean contains(PathIterator2f pi, float rx, float ry, float rwidth, float rheight) {
+		// Copied from AWT API
+        if (rwidth <= 0 || rheight <= 0) {
+            return false;
+        }
+        int mask = (pi.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 2);
+        int crossings = computeCrossingsFromRect(pi, rx, ry, rx+rwidth, ry+rheight);
+        return (crossings != MathConstants.SHAPE_INTERSECTS &&
+                (crossings & mask) != 0);
+	}
+
+	/**
+	 * Tests if the interior of the specified {@link PathIterator2f}
+	 * intersects the interior of a specified set of rectangular
+	 * coordinates.
+	 * <p>
+	 * This method provides a basic facility for implementors of
+	 * the {@link Shape2f} interface to implement support for the
+	 * {@code intersects()} method.
+	 * <p>
+	 * This method object may conservatively return true in
+	 * cases where the specified rectangular area intersects a
+	 * segment of the path, but that segment does not represent a
+	 * boundary between the interior and exterior of the path.
+	 * Such a case may occur if some set of segments of the
+	 * path are retraced in the reverse direction such that the
+	 * two sets of segments cancel each other out without any
+	 * interior area between them.
+	 * To determine whether segments represent true boundaries of
+	 * the interior of the path would require extensive calculations
+	 * involving all of the segments of the path and the winding
+	 * rule and are thus beyond the scope of this implementation.
+	 *
+	 * @param pi the specified {@code PathIterator}
+	 * @param x the specified X coordinate
+	 * @param y the specified Y coordinate
+	 * @param w the width of the specified rectangular coordinates
+	 * @param h the height of the specified rectangular coordinates
+	 * @return {@code true} if the specified {@code PathIterator} and
+	 *         the interior of the specified set of rectangular
+	 *         coordinates intersect each other; {@code false} otherwise.
+	 */
+	public static boolean intersects(PathIterator2f pi, float x, float y, float w, float h) {
+		if (w <= 0f || h <= 0f) {
+			return false;
+		}
+		int mask = (pi.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 2);
+		int crossings = computeCrossingsFromRect(pi, x, y, x+w, y+h);
+		return (crossings == MathConstants.SHAPE_INTERSECTS ||
+				(crossings & mask) != 0);
+	}
+
+	/**
+	 * Calculates the number of times the given path
+	 * crosses the ray extending to the right from (px,py).
+	 * If the point lies on a part of the path,
+	 * then no crossings are counted for that intersection.
+	 * +1 is added for each crossing where the Y coordinate is increasing
+	 * -1 is added for each crossing where the Y coordinate is decreasing
+	 * The return value is the sum of all crossings for every segment in
+	 * the path.
+	 * The path must start with a MOVE_TO, otherwise an exception is
+	 * thrown.
+	 * 
+	 * @param pi is the description of the path.
+	 * @param px is the reference point to test.
+	 * @param py is the reference point to test.
+	 * @return the crossing
+	 */
+	public static int computeCrossingsFromPoint(PathIterator2f pi, float px, float py) {
+		// Copied from the AWT API
+		if (!pi.hasNext()) return 0;
+		PathElement2f element;
+
+		element = pi.next();
+		if (element.type != PathElementType.MOVE_TO) {
+			throw new IllegalArgumentException("missing initial moveto in path definition"); //$NON-NLS-1$
+		}
+
+		float movx = element.toX;
+		float movy = element.toY;
+		float curx = movx;
+		float cury = movy;
+		float endx, endy;
+		int crossings = 0;
+		while (pi.hasNext()) {
+			element = pi.next();
+			switch (element.type) {
+			case MOVE_TO:
+				movx = curx = element.toX;
+				movy = cury = element.toY;
+				break;
+			case LINE_TO:
+				endx = element.toX;
+				endy = element.toY;
+				crossings += Segment2f.computeCrossingsFromPoint(
+						px, py,
+						curx, cury,
+						endx, endy);
+				curx = endx;
+				cury = endy;
+				break;
+			case QUAD_TO:
+				endx = element.toX;
+				endy = element.toY;
+				crossings += computeQuadCurveCrossingsFromPoint(
+						px, py,
+						curx, cury,
+						element.ctrlX1, element.ctrlY1,
+						endx, endy, 0);
+				curx = endx;
+				cury = endy;
+				break;
+			case CURVE_TO:
+				endx = element.toX;
+				endy = element.toY;
+				crossings += computeCubicCurveCrossingsFromPoint(
+						px, py,
+						curx, cury,
+						element.ctrlX1, element.ctrlY1,
+						element.ctrlX2, element.ctrlY2,
+						endx, endy, 0);
+				curx = endx;
+				cury = endy;
+				break;
+			case CLOSE:
+				if (cury != movy || curx != movx) {
+					crossings += Segment2f.computeCrossingsFromPoint(
+							px, py,
+							curx, cury,
+							movx, movy);
+				}
+				curx = movx;
+				cury = movy;
+				break;
+			default:
+			}
+		}
+
+		if (cury != movy) {
+			crossings += Segment2f.computeCrossingsFromPoint(
+					px, py,
+					curx, cury,
+					movx, movy);
+		}
+		return crossings;
+	}
+
+	/**
+	 * Calculates the number of times the given path
+	 * crosses the given ellipse extending to the right.
+	 * 
+	 * @param pi is the description of the path.
+	 * @param ex is the first point of the ellipse.
+	 * @param ey is the first point of the ellipse.
+	 * @param ew is the width of the ellipse.
+	 * @param eh is the height of the ellipse.
+	 * @return the crossing or {@link MathConstants#SHAPE_INTERSECTS}
+	 */
+	public static int computeCrossingsFromEllipse(PathIterator2f pi, float ex, float ey, float ew, float eh) {
+		return computeCrossingsFromEllipse(0, pi, ex, ey, ew, eh, true);
+	}
+	
+	/**
+	 * Calculates the number of times the given path
+	 * crosses the given ellipse extending to the right.
+	 * 
+	 * @param crossings is the initial value for crossing.
+	 * @param pi is the description of the path.
+	 * @param ex is the first point of the ellipse.
+	 * @param ey is the first point of the ellipse.
+	 * @param ew is the width of the ellipse.
+	 * @param eh is the height of the ellipse.
+	 * @param closeable indicates if the shape is automatically closed or not.
+	 * @return the crossing or {@link MathConstants#SHAPE_INTERSECTS}
+	 */
+	static int computeCrossingsFromEllipse(int crossings, PathIterator2f pi, float ex, float ey, float ew, float eh, boolean closeable) {	
+		// Copied from the AWT API
+		if (!pi.hasNext()) return 0;
+		PathElement2f element;
+
+		element = pi.next();
+		if (element.type != PathElementType.MOVE_TO) {
+			throw new IllegalArgumentException("missing initial moveto in path definition"); //$NON-NLS-1$
+		}
+
+		float movx = element.toX;
+		float movy = element.toY;
+		float curx = movx;
+		float cury = movy;
+		float endx, endy;
+		int numCrosses = crossings;
+		while (numCrosses!=MathConstants.SHAPE_INTERSECTS && pi.hasNext()) {
+			element = pi.next();
+			switch (element.type) {
+			case MOVE_TO:
+				movx = curx = element.toX;
+				movy = cury = element.toY;
+				break;
+			case LINE_TO:
+				endx = element.toX;
+				endy = element.toY;
+				numCrosses = Segment2f.computeCrossingsFromEllipse(
+						numCrosses,
+						ex, ey, ew, eh,
+						curx, cury,
+						endx, endy);
+				curx = endx;
+				cury = endy;
+				break;
+			case QUAD_TO:
+			{
+				endx = element.toX;
+				endy = element.toY;
+				Path2f localPath = new Path2f();
+				localPath.moveTo(element.fromX, element.fromY);
+				localPath.quadTo(
+						element.ctrlX1, element.ctrlY1,
+						endx, endy);
+				numCrosses = computeCrossingsFromEllipse(
+						numCrosses,
+						localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+						ex, ey, ew, eh,
+						false);
+				curx = endx;
+				cury = endy;
+				break;
+			}
+			case CURVE_TO:
+				endx = element.toX;
+				endy = element.toY;
+				Path2f localPath = new Path2f();
+				localPath.moveTo(element.fromX, element.fromY);
+				localPath.curveTo(
+						element.ctrlX1, element.ctrlY1,
+						element.ctrlX2, element.ctrlY2,
+						endx, endy);
+				numCrosses = computeCrossingsFromEllipse(
+						numCrosses,
+						localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+						ex, ey, ew, eh,
+						false);
+				curx = endx;
+				cury = endy;
+				break;
+			case CLOSE:
+				if (cury != movy || curx != movx) {
+					numCrosses = Segment2f.computeCrossingsFromEllipse(
+							numCrosses,
+							ex, ey, ew, eh,
+							curx, cury,
+							movx, movy);
+				}
+				curx = movx;
+				cury = movy;
+				break;
+			default:
+			}
+		}
+
+		if (numCrosses!=MathConstants.SHAPE_INTERSECTS && closeable && cury != movy) {
+			numCrosses = Segment2f.computeCrossingsFromEllipse(
+					numCrosses,
+					ex, ey, ew, eh,
+					curx, cury,
+					movx, movy);
+		}
+		
+		return numCrosses;
+	}
+
+	/**
+	 * Calculates the number of times the given path
+	 * crosses the given ellipse extending to the right.
+	 * 
+	 * @param pi is the description of the path.
+	 * @param cx is the center of the circle.
+	 * @param cy is the center of the circle.
+	 * @param radius is the radius of the circle.
+	 * @return the crossing or {@link MathConstants#SHAPE_INTERSECTS}.
+	 */
+	public static int computeCrossingsFromCircle(PathIterator2f pi, float cx, float cy, float radius) {
+		return computeCrossingsFromCircle(0, pi, cx, cy, radius, true);
+	}
+	
+	/**
+	 * Calculates the number of times the given path
+	 * crosses the given circle extending to the right.
+	 * 
+	 * @param crossings is the initial value for crossing.
+	 * @param pi is the description of the path.
+	 * @param cx is the center of the circle.
+	 * @param cy is the center of the circle.
+	 * @param radius is the radius of the circle.
+	 * @param closeable indicates if the shape is automatically closed or not.
+	 * @return the crossing
+	 */
+	static int computeCrossingsFromCircle(int crossings, PathIterator2f pi, float cx, float cy, float radius, boolean closeable) {	
+		// Copied from the AWT API
+		if (!pi.hasNext()) return 0;
+		PathElement2f element;
+
+		element = pi.next();
+		if (element.type != PathElementType.MOVE_TO) {
+			throw new IllegalArgumentException("missing initial moveto in path definition"); //$NON-NLS-1$
+		}
+
+		float movx = element.toX;
+		float movy = element.toY;
+		float curx = movx;
+		float cury = movy;
+		float endx, endy;
+		int numCrosses = crossings;
+		while (numCrosses!=MathConstants.SHAPE_INTERSECTS && pi.hasNext()) {
+			element = pi.next();
+			switch (element.type) {
+			case MOVE_TO:
+				movx = curx = element.toX;
+				movy = cury = element.toY;
+				break;
+			case LINE_TO:
+				endx = element.toX;
+				endy = element.toY;
+				numCrosses = Segment2f.computeCrossingsFromCircle(
+						numCrosses,
+						cx, cy, radius,
+						curx, cury,
+						endx, endy);
+				curx = endx;
+				cury = endy;
+				break;
+			case QUAD_TO:
+			{
+				endx = element.toX;
+				endy = element.toY;
+				Path2f localPath = new Path2f();
+				localPath.moveTo(element.fromX, element.fromY);
+				localPath.quadTo(
+						element.ctrlX1, element.ctrlY1,
+						endx, endy);
+				numCrosses = computeCrossingsFromCircle(
+						numCrosses,
+						localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+						cx, cy, radius,
+						false);
+				curx = endx;
+				cury = endy;
+				break;
+			}
+			case CURVE_TO:
+				endx = element.toX;
+				endy = element.toY;
+				Path2f localPath = new Path2f();
+				localPath.moveTo(element.fromX, element.fromY);
+				localPath.curveTo(
+						element.ctrlX1, element.ctrlY1,
+						element.ctrlX2, element.ctrlY2,
+						endx, endy);
+				numCrosses = computeCrossingsFromCircle(
+						numCrosses,
+						localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+						cx, cy, radius,
+						false);
+				curx = endx;
+				cury = endy;
+				break;
+			case CLOSE:
+				if (cury != movy || curx != movx) {
+					numCrosses = Segment2f.computeCrossingsFromCircle(
+							numCrosses,
+							cx, cy, radius,
+							curx, cury,
+							movx, movy);
+				}
+				curx = movx;
+				cury = movy;
+				break;
+			default:
+			}
+		}
+
+		if (numCrosses!=MathConstants.SHAPE_INTERSECTS && closeable && cury != movy) {
+			numCrosses = Segment2f.computeCrossingsFromCircle(
+					numCrosses,
+					cx, cy, radius,
+					curx, cury,
+					movx, movy);
+		}
+		
+		return numCrosses;
+	}
+
+	/**
+	 * Calculates the number of times the given path
+	 * crosses the given segment extending to the right.
+	 * 
+	 * @param pi is the description of the path.
+	 * @param x1 is the first point of the segment.
+	 * @param y1 is the first point of the segment.
+	 * @param x2 is the first point of the segment.
+	 * @param y2 is the first point of the segment.
+	 * @return the crossing or {@link MathConstants#SHAPE_INTERSECTS}.
+	 */
+	public static int computeCrossingsFromSegment(PathIterator2f pi, float x1, float y1, float x2, float y2) {
+		return computeCrossingsFromSegment(0, pi, x1, y1, x2, y2, true);
+	}
+	
+	/**
+	 * Calculates the number of times the given path
+	 * crosses the given circle extending to the right.
+	 * 
+	 * @param crossings is the initial value for crossing.
+	 * @param pi is the description of the path.
+	 * @param x1 is the first point of the segment.
+	 * @param y1 is the first point of the segment.
+	 * @param x2 is the first point of the segment.
+	 * @param y2 is the first point of the segment.
+	 * @param closeable indicates if the shape is automatically closed or not.
+	 * @return the crossing
+	 */
+	static int computeCrossingsFromSegment(int crossings, PathIterator2f pi, float x1, float y1, float x2, float y2, boolean closeable) {	
+		// Copied from the AWT API
+		if (!pi.hasNext()) return 0;
+		PathElement2f element;
+
+		element = pi.next();
+		if (element.type != PathElementType.MOVE_TO) {
+			throw new IllegalArgumentException("missing initial moveto in path definition"); //$NON-NLS-1$
+		}
+
+		float movx = element.toX;
+		float movy = element.toY;
+		float curx = movx;
+		float cury = movy;
+		float endx, endy;
+		int numCrosses = crossings;
+		while (numCrosses!=MathConstants.SHAPE_INTERSECTS && pi.hasNext()) {
+			element = pi.next();
+			switch (element.type) {
+			case MOVE_TO:
+				movx = curx = element.toX;
+				movy = cury = element.toY;
+				break;
+			case LINE_TO:
+				endx = element.toX;
+				endy = element.toY;
+				numCrosses = Segment2f.computeCrossingsFromSegment(
+						numCrosses,
+						x1, y1, x2, y2,
+						curx, cury,
+						endx, endy);
+				curx = endx;
+				cury = endy;
+				break;
+			case QUAD_TO:
+			{
+				endx = element.toX;
+				endy = element.toY;
+				Path2f localPath = new Path2f();
+				localPath.moveTo(element.fromX, element.fromY);
+				localPath.quadTo(
+						element.ctrlX1, element.ctrlY1,
+						endx, endy);
+				numCrosses = computeCrossingsFromSegment(
+						numCrosses,
+						localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+						x1, y1, x2, y2,
+						false);
+				curx = endx;
+				cury = endy;
+				break;
+			}
+			case CURVE_TO:
+				endx = element.toX;
+				endy = element.toY;
+				Path2f localPath = new Path2f();
+				localPath.moveTo(element.fromX, element.fromY);
+				localPath.curveTo(
+						element.ctrlX1, element.ctrlY1,
+						element.ctrlX2, element.ctrlY2,
+						endx, endy);
+				numCrosses = computeCrossingsFromSegment(
+						numCrosses,
+						localPath.getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO),
+						x1, y1, x2, y2,
+						false);
+				curx = endx;
+				cury = endy;
+				break;
+			case CLOSE:
+				if (cury != movy || curx != movx) {
+					numCrosses = Segment2f.computeCrossingsFromSegment(
+							numCrosses,
+							x1, y1, x2, y2,
+							curx, cury,
+							movx, movy);
+				}
+				curx = movx;
+				cury = movy;
+				break;
+			default:
+			}
+		}
+
+		if (numCrosses!=MathConstants.SHAPE_INTERSECTS && closeable && cury != movy) {
+			numCrosses = Segment2f.computeCrossingsFromSegment(
+					numCrosses,
+					x1, y1, x2, y2,
+					curx, cury,
+					movx, movy);
+		}
+		
+		return numCrosses;
+	}
+
+	/**
+	 * Calculates the number of times the quad from (x0,y0) to (x1,y1)
+	 * crosses the ray extending to the right from (px,py).
+	 * If the point lies on a part of the curve,
+	 * then no crossings are counted for that intersection.
+	 * the level parameter should be 0 at the top-level call and will count
+	 * up for each recursion level to prevent infinite recursion
+	 * +1 is added for each crossing where the Y coordinate is increasing
+	 * -1 is added for each crossing where the Y coordinate is decreasing
+	 * 
+	 * @param px is the reference point to test.
+	 * @param py is the reference point to test.
+	 * @param x0 is the first point of the quad curve.
+	 * @param y0 is the first point of the quad curve.
+	 * @param xc is the control point of the quad curve.
+	 * @param yc is the control point of the quad curve.
+	 * @param x1 is the last point of the quad curve.
+	 * @param y1 is the last point of the quad curve.
+	 * @param level may be zero.
+	 * @return the crossing.
+	 */
+	static int computeQuadCurveCrossingsFromPoint(float px, float py,
+			float x0, float y0,
+			float xc, float yc,
+			float x1, float y1,
+			int level) {
+		// Copied from AWT API
+		if (py <  y0 && py <  yc && py <  y1) return 0;
+		if (py >= y0 && py >= yc && py >= y1) return 0;
+		// Note y0 could equal y1...
+		if (px >= x0 && px >= xc && px >= x1) return 0;
+		if (px <  x0 && px <  xc && px <  x1) {
+			if (py >= y0) {
+				if (py < y1) return 1;
+			} else {
+				// py < y0
+				if (py >= y1) return -1;
+			}
+			// py outside of y01 range, and/or y0==y1
+			return 0;
+		}
+		// float precision only has 52 bits of mantissa
+		if (level > 52) return Segment2f.computeCrossingsFromPoint(px, py, x0, y0, x1, y1);
+		float x0c = (x0 + xc) / 2;
+		float y0c = (y0 + yc) / 2;
+		float xc1 = (xc + x1) / 2;
+		float yc1 = (yc + y1) / 2;
+		float nxc = (x0c + xc1) / 2;
+		float nyc = (y0c + yc1) / 2;
+		if (Double.isNaN(nxc) || Double.isNaN(nyc)) {
+			// [xy]c are NaN if any of [xy]0c or [xy]c1 are NaN
+			// [xy]0c or [xy]c1 are NaN if any of [xy][0c1] are NaN
+			// These values are also NaN if opposing infinities are added
+			return 0;
+		}
+		return (computeQuadCurveCrossingsFromPoint(px, py,
+				x0, y0, x0c, y0c, nxc, nyc,
+				level+1) +
+				computeQuadCurveCrossingsFromPoint(px, py,
+						nxc, nyc, xc1, yc1, x1, y1,
+						level+1));
+	}
+
+	/**
+	 * Calculates the number of times the cubic from (x0,y0) to (x1,y1)
+	 * crosses the ray extending to the right from (px,py).
+	 * If the point lies on a part of the curve,
+	 * then no crossings are counted for that intersection.
+	 * the level parameter should be 0 at the top-level call and will count
+	 * up for each recursion level to prevent infinite recursion
+	 * +1 is added for each crossing where the Y coordinate is increasing
+	 * 
+	 * @param px is the reference point to test.
+	 * @param py is the reference point to test.
+	 * @param x0 is the first point of the quad curve.
+	 * @param y0 is the first point of the quad curve.
+	 * @param xc0 is the first control point of the cubic curve.
+	 * @param yc0 is the first control point of the cubic curve.
+	 * @param xc1 is the second control point of the cubic curve.
+	 * @param yc1 is the second control point of the cubic curve.
+	 * @param x1 is the last point of the quad curve.
+	 * @param y1 is the last point of the quad curve.
+	 * @param level may be zero.
+	 * @return the crossing.
+	 * -1 is added for each crossing where the Y coordinate is decreasing
+	 */
+	static int computeCubicCurveCrossingsFromPoint(
+			float px, float py,
+			float x0, float y0,
+			float xc0, float yc0,
+			float xc1, float yc1,
+			float x1, float y1,
+			int level) {
+		// Copied from AWT API
+		if (py <  y0 && py <  yc0 && py <  yc1 && py <  y1) return 0;
+		if (py >= y0 && py >= yc0 && py >= yc1 && py >= y1) return 0;
+		// Note y0 could equal yc0...
+		if (px >= x0 && px >= xc0 && px >= xc1 && px >= x1) return 0;
+		if (px <  x0 && px <  xc0 && px <  xc1 && px <  x1) {
+			if (py >= y0) {
+				if (py < y1) return 1;
+			} else {
+				// py < y0
+				if (py >= y1) return -1;
+			}
+			// py outside of y01 range, and/or y0==yc0
+			return 0;
+		}
+		// float precision only has 52 bits of mantissa
+		if (level > 52) return Segment2f.computeCrossingsFromPoint(px, py, x0, y0, x1, y1);
+		float xmid = (xc0 + xc1) / 2;
+		float ymid = (yc0 + yc1) / 2;
+		float nxc0 = (x0 + xc0) / 2;
+		float nyc0 = (y0 + yc0) / 2;
+		float nxc1 = (xc1 + x1) / 2;
+		float nyc1 = (yc1 + y1) / 2;
+		float xc0m = (nxc0 + xmid) / 2;
+		float yc0m = (nyc0 + ymid) / 2;
+		float xmc1 = (xmid + nxc1) / 2;
+		float ymc1 = (ymid + nyc1) / 2;
+		xmid = (xc0m + xmc1) / 2;
+		ymid = (yc0m + ymc1) / 2;
+		if (Double.isNaN(xmid) || Double.isNaN(ymid)) {
+			// [xy]mid are NaN if any of [xy]c0m or [xy]mc1 are NaN
+			// [xy]c0m or [xy]mc1 are NaN if any of [xy][c][01] are NaN
+			// These values are also NaN if opposing infinities are added
+			return 0;
+		}
+		return (computeCubicCurveCrossingsFromPoint(px, py,
+				x0, y0, nxc0, nyc0,
+				xc0m, yc0m, xmid, ymid, level+1) +
+				computeCubicCurveCrossingsFromPoint(px, py,
+						xmid, ymid, xmc1, ymc1,
+						nxc1, nyc1, x1, y1, level+1));
+	}
+
+	/**
+	 * Accumulate the number of times the path crosses the shadow
+	 * extending to the right of the rectangle.  See the comment
+	 * for the RECT_INTERSECTS constant for more complete details.
+	 * The return value is the sum of all crossings for both the
+	 * top and bottom of the shadow for every segment in the path,
+	 * or the special value RECT_INTERSECTS if the path ever enters
+	 * the interior of the rectangle.
+	 * The path must start with a SEG_MOVETO, otherwise an exception is
+	 * thrown.
+	 * The caller must check r[xy]{min,max} for NaN values.
+	 * 
+	 * @param pi is the iterator on the path elements.
+	 * @param rxmin is the first corner of the rectangle.
+	 * @param rymin is the first corner of the rectangle.
+	 * @param rxmax is the second corner of the rectangle.
+	 * @param rymax is the second corner of the rectangle.
+	 * @return the crossings.
+	 */
+	public static int computeCrossingsFromRect(PathIterator2f pi,
+			float rxmin, float rymin,
+			float rxmax, float rymax) {
+		// Copied from AWT API
+		if (rxmax <= rxmin || rymax <= rymin) return 0;
+		if (!pi.hasNext()) return 0;
+
+		PathElement2f pathElement = pi.next();
+
+		if (pathElement.type != PathElementType.MOVE_TO) {
+			throw new IllegalArgumentException("missing initial moveto in path definition"); //$NON-NLS-1$
+		}
+
+		float curx, cury, movx, movy, endx, endy;
+		curx = movx = pathElement.toX;
+		cury = movy = pathElement.toY;
+		int crossings = 0;
+
+		while (crossings != MathConstants.SHAPE_INTERSECTS
+				&& pi.hasNext()) {
+			pathElement = pi.next();
+			switch (pathElement.type) {
+			case MOVE_TO:
+				// Count should always be a multiple of 2 here.
+				// assert((crossings & 1) != 0);
+				movx = curx = pathElement.toX;
+				movy = cury = pathElement.toY;
+				break;
+			case LINE_TO:
+				endx = pathElement.toX;
+				endy = pathElement.toY;
+				crossings = Segment2f.computeCrossingsFromRect(crossings,
+						rxmin, rymin,
+						rxmax, rymax,
+						curx, cury,
+						endx, endy);
+				curx = endx;
+				cury = endy;
+				break;
+			case QUAD_TO:
+				endx = pathElement.toX;
+				endy = pathElement.toY;
+				crossings = computeQuadCurveCrossingsFromRect(crossings,
+						rxmin, rymin,
+						rxmax, rymax,
+						curx, cury,
+						pathElement.ctrlX1, pathElement.ctrlY1,
+						endx, endy, 0);
+				curx = endx;
+				cury = endy;
+				break;
+			case CURVE_TO:
+				endx = pathElement.toX;
+				endy = pathElement.toY;
+				crossings = computeCubicCurveCrossingsFromRect(crossings,
+						rxmin, rymin,
+						rxmax, rymax,
+						curx, cury,
+						pathElement.ctrlX1, pathElement.ctrlY1,
+						pathElement.ctrlX2, pathElement.ctrlY2,
+						endx, endy, 0);
+				curx = endx;
+				cury = endy;
+				break;
+			case CLOSE:
+				if (curx != movx || cury != movy) {
+					crossings = Segment2f.computeCrossingsFromRect(crossings,
+							rxmin, rymin,
+							rxmax, rymax,
+							curx, cury,
+							movx, movy);
+				}
+				curx = movx;
+				cury = movy;
+				// Count should always be a multiple of 2 here.
+				// assert((crossings & 1) != 0);
+				break;
+			default:
+			}
+		}
+
+		if (crossings != MathConstants.SHAPE_INTERSECTS && (curx != movx || cury != movy)) {
+			crossings = Segment2f.computeCrossingsFromRect(crossings,
+					rxmin, rymin,
+					rxmax, rymax,
+					curx, cury,
+					movx, movy);
+		}
+
+		// Count should always be a multiple of 2 here.
+		// assert((crossings & 1) != 0);
+		return crossings;
+	}
+
+	/**
+	 * Accumulate the number of times the quad crosses the shadow
+	 * extending to the right of the rectangle.  See the comment
+	 * for the RECT_INTERSECTS constant for more complete details.
+	 * 
+	 * @param crossings is the initial value for the crossings.
+	 * @param rxmin is the first corner of the rectangle.
+	 * @param rymin is the first corner of the rectangle.
+	 * @param rxmax is the second corner of the rectangle.
+	 * @param rymax is the second corner of the rectangle.
+	 * @param x0 is the first point of the curve.
+	 * @param y0 is the first point of the curve.
+	 * @param xc is the control point of the curve.
+	 * @param yc is the control point of the curve.
+	 * @param x1 is the last point of the curve.
+	 * @param y1 is the last point of the curve.
+	 * @param level is the recursion level. It may be equal to {@code 0} for the intiial call.
+	 * @return the crossings.
+	 */
+	static int computeQuadCurveCrossingsFromRect(
+			int crossings,
+			float rxmin, float rymin,
+			float rxmax, float rymax,
+			float x0, float y0,
+			float xc, float yc,
+			float x1, float y1,
+			int level) {
+		// Copied from AWT API
+		float ctrlx = xc;
+		float ctrly = yc;
+		int numCrosses = crossings;
+
+		if (y0 >= rymax && ctrly >= rymax && y1 >= rymax) return numCrosses;
+		if (y0 <= rymin && ctrly <= rymin && y1 <= rymin) return numCrosses;
+		if (x0 <= rxmin && ctrlx <= rxmin && x1 <= rxmin) return numCrosses;
+		if (x0 >= rxmax && ctrlx >= rxmax && x1 >= rxmax) {
+			// Quad is entirely to the right of the rect
+			// and the vertical range of the 3 Y coordinates of the quad
+			// overlaps the vertical range of the rect by a non-empty amount
+			// We now judge the crossings solely based on the line segment
+			// connecting the endpoints of the quad.
+			// Note that we may have 0, 1, or 2 crossings as the control
+			// point may be causing the Y range intersection while the
+			// two endpoints are entirely above or below.
+			if (y0 < y1) {
+				// y-increasing line segment...
+				if (y0 <= rymin && y1 >  rymin) ++numCrosses;
+				if (y0 <  rymax && y1 >= rymax) ++numCrosses;
+			}
+			else if (y1 < y0) {
+				// y-decreasing line segment...
+				if (y1 <= rymin && y0 >  rymin) --numCrosses;
+				if (y1 <  rymax && y0 >= rymax) --numCrosses;
+			}
+			return numCrosses;
+		}
+
+		// The intersection of ranges is more complicated
+		// First do trivial INTERSECTS rejection of the cases
+		// where one of the endpoints is inside the rectangle.
+		if ((x0 < rxmax && x0 > rxmin && y0 < rymax && y0 > rymin) ||
+				(x1 < rxmax && x1 > rxmin && y1 < rymax && y1 > rymin)) {
+			return MathConstants.SHAPE_INTERSECTS;
+		}
+		// Otherwise, subdivide and look for one of the cases above.
+		// float precision only has 52 bits of mantissa
+		if (level > 52) {
+			return Segment2f.computeCrossingsFromRect(numCrosses,
+					rxmin, rymin, rxmax, rymax,
+					x0, y0, x1, y1);
+		}
+		float x0c = (x0 + ctrlx) / 2;
+		float y0c = (y0 + ctrly) / 2;
+		float xc1 = (ctrlx + x1) / 2;
+		float yc1 = (ctrly + y1) / 2;
+		ctrlx = (x0c + xc1) / 2;
+		ctrly = (y0c + yc1) / 2;
+		if (Double.isNaN(ctrlx) || Double.isNaN(ctrly)) {
+			// [xy]c are NaN if any of [xy]0c or [xy]c1 are NaN
+			// [xy]0c or [xy]c1 are NaN if any of [xy][0c1] are NaN
+			// These values are also NaN if opposing infinities are added
+			return 0;
+		}
+		numCrosses = computeQuadCurveCrossingsFromRect(numCrosses,
+				rxmin, rymin, rxmax, rymax,
+				x0, y0, x0c, y0c, ctrlx, ctrly,
+				level+1);
+		if (numCrosses != MathConstants.SHAPE_INTERSECTS) {
+			numCrosses = computeQuadCurveCrossingsFromRect(numCrosses,
+					rxmin, rymin, rxmax, rymax,
+					ctrlx, ctrly, xc1, yc1, x1, y1,
+					level+1);
+		}
+		return numCrosses;
+	}
+
+	/**
+	 * Accumulate the number of times the cubic crosses the shadow
+	 * extending to the right of the rectangle.  See the comment
+	 * for the RECT_INTERSECTS constant for more complete details.
+	 * 
+	 * @param crossings is the initial value for the crossings.
+	 * @param rxmin is the first corner of the rectangle.
+	 * @param rymin is the first corner of the rectangle.
+	 * @param rxmax is the second corner of the rectangle.
+	 * @param rymax is the second corner of the rectangle.
+	 * @param x0 is the first point of the curve.
+	 * @param y0 is the first point of the curve.
+	 * @param xc0 is the first control point of the curve.
+	 * @param yc0 is the first control point of the curve.
+	 * @param xc1 is the second control point of the curve.
+	 * @param yc1 is the second control point of the curve.
+	 * @param x1 is the last point of the curve.
+	 * @param y1 is the last point of the curve.
+	 * @param level is the recursion level. It may be equal to {@code 0} for the intiial call.
+	 * @return the crossings.
+	 */
+	static int computeCubicCurveCrossingsFromRect(
+			int crossings,
+			float rxmin, float rymin,
+			float rxmax, float rymax,
+			float x0,  float y0,
+			float xc0, float yc0,
+			float xc1, float yc1,
+			float x1,  float y1,
+			int level) {
+		// Copied from AWT API
+		float ctrlx0 = xc0;
+		float ctrly0 = yc0;
+		float ctrlx1 = xc1;
+		float ctrly1 = yc1;
+		int numCrosses = crossings;
+
+		if (y0 >= rymax && ctrly0 >= rymax && ctrly1 >= rymax && y1 >= rymax) {
+			return numCrosses;
+		}
+		if (y0 <= rymin && ctrly0 <= rymin && ctrly1 <= rymin && y1 <= rymin) {
+			return numCrosses;
+		}
+		if (x0 <= rxmin && ctrlx0 <= rxmin && ctrlx1 <= rxmin && x1 <= rxmin) {
+			return numCrosses;
+		}
+		if (x0 >= rxmax && ctrlx0 >= rxmax && ctrlx1 >= rxmax && x1 >= rxmax) {
+			// Cubic is entirely to the right of the rect
+			// and the vertical range of the 4 Y coordinates of the cubic
+			// overlaps the vertical range of the rect by a non-empty amount
+			// We now judge the crossings solely based on the line segment
+			// connecting the endpoints of the cubic.
+			// Note that we may have 0, 1, or 2 crossings as the control
+			// points may be causing the Y range intersection while the
+			// two endpoints are entirely above or below.
+			if (y0 < y1) {
+				// y-increasing line segment...
+				if (y0 <= rymin && y1 >  rymin) ++numCrosses;
+				if (y0 <  rymax && y1 >= rymax) ++numCrosses;
+			}
+			else if (y1 < y0) {
+				// y-decreasing line segment...
+				if (y1 <= rymin && y0 >  rymin) --numCrosses;
+				if (y1 <  rymax && y0 >= rymax) --numCrosses;
+			}
+			return numCrosses;
+		}
+		// The intersection of ranges is more complicated
+		// First do trivial INTERSECTS rejection of the cases
+		// where one of the endpoints is inside the rectangle.
+		if ((x0 > rxmin && x0 < rxmax && y0 > rymin && y0 < rymax) ||
+				(x1 > rxmin && x1 < rxmax && y1 > rymin && y1 < rymax)) {
+			return MathConstants.SHAPE_INTERSECTS;
+		}
+		// Otherwise, subdivide and look for one of the cases above.
+		// float precision only has 52 bits of mantissa
+		if (level > 52) {
+			return Segment2f.computeCrossingsFromRect(numCrosses,
+					rxmin, rymin, rxmax, rymax,
+					x0, y0, x1, y1);
+		}
+		float xmid = (ctrlx0 + ctrlx1) / 2;
+		float ymid = (ctrly0 + ctrly1) / 2;
+		ctrlx0 = (x0 + ctrlx0) / 2;
+		ctrly0 = (y0 + ctrly0) / 2;
+		ctrlx1 = (ctrlx1 + x1) / 2;
+		ctrly1 = (ctrly1 + y1) / 2;
+		float xc0m = (ctrlx0 + xmid) / 2;
+		float yc0m = (ctrly0 + ymid) / 2;
+		float xmc1 = (xmid + ctrlx1) / 2;
+		float ymc1 = (ymid + ctrly1) / 2;
+		xmid = (xc0m + xmc1) / 2;
+		ymid = (yc0m + ymc1) / 2;
+		if (Double.isNaN(xmid) || Double.isNaN(ymid)) {
+			// [xy]mid are NaN if any of [xy]c0m or [xy]mc1 are NaN
+			// [xy]c0m or [xy]mc1 are NaN if any of [xy][c][01] are NaN
+			// These values are also NaN if opposing infinities are added
+			return 0;
+		}
+		numCrosses = computeCubicCurveCrossingsFromRect(numCrosses,
+				rxmin, rymin, rxmax, rymax,
+				x0, y0, ctrlx0, ctrly0,
+				xc0m, yc0m, xmid, ymid, level+1);
+		if (numCrosses != MathConstants.SHAPE_INTERSECTS) {
+			numCrosses = computeCubicCurveCrossingsFromRect(numCrosses,
+					rxmin, rymin, rxmax, rymax,
+					xmid, ymid, xmc1, ymc1,
+					ctrlx1, ctrly1, x1, y1, level+1);
+		}
+		return crossings;
+	}
+
+	/** Array of types.
+	 */
+	PathElementType[] types;
+
+	/** Array of coords.
+	 */
+	float[] coords;
+
+	/** Number of types in the array.
+	 */
+	int numTypes = 0;
+
+	/** Number of coords in the array.
+	 */
+	int numCoords = 0;
+
+	/** Winding rule for the path.
+	 */
+	PathWindingRule windingRule;
+	
+	/** Indicates if the path is empty.
+	 * The path is empty when there is no point inside, or
+	 * all the points are at the same coordinate, or
+	 * when the path does not represents a drawable path
+	 * (a path with a line or a curve).
+	 */
+	private Boolean isEmpty = Boolean.TRUE;
+	
+	/** Buffer for the bounds of the path.
+	 */
+	private SoftReference<Rectangle2f> bounds = null;
+
+	/**
+	 */
+	public Path2f() {
+		this(PathWindingRule.NON_ZERO);
+	}
+
+	/**
+	 * @param iterator
+	 */
+	public Path2f(Iterator<PathElement2f> iterator) {
+		this(PathWindingRule.NON_ZERO, iterator);
+	}
+
+	/**
+	 * @param windingRule
+	 */
+	public Path2f(PathWindingRule windingRule) {
+		assert(windingRule!=null);
+		this.types = new PathElementType[GROW_SIZE];
+		this.coords = new float[GROW_SIZE];
+		this.windingRule = windingRule;
+	}
+
+	/**
+	 * @param windingRule
+	 * @param iterator
+	 */
+	public Path2f(PathWindingRule windingRule, Iterator<PathElement2f> iterator) {
+		assert(windingRule!=null);
+		this.types = new PathElementType[GROW_SIZE];
+		this.coords = new float[GROW_SIZE];
+		this.windingRule = windingRule;
+		add(iterator);
+	}
+	
+	@Override
+	public void clear() {
+		this.types = new PathElementType[GROW_SIZE];
+		this.coords = new float[GROW_SIZE];
+		this.windingRule = PathWindingRule.NON_ZERO;
+		this.numCoords = 0;
+		this.numTypes = 0;
+		this.isEmpty = true;
+		this.bounds = null;
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append("["); //$NON-NLS-1$
+		if (this.numCoords>0) {
+			b.append(this.coords[0]);
+			for(int i=1; i<this.numCoords; ++i) {
+				b.append(", "); //$NON-NLS-1$
+				b.append(this.coords[i]);
+			}
+		}
+		b.append("]"); //$NON-NLS-1$
+		return b.toString();
+	}
+
+	@Override
+	public Path2f clone() {
+		Path2f clone = super.clone();
+		clone.coords = this.coords.clone();
+		clone.types = this.types.clone();
+		return clone;
+	}
+
+	/** Replies the winding rule for the path.
+	 * 
+	 * @return the winding rule for the path.
+	 */
+	public PathWindingRule getWindingRule() {
+		return this.windingRule;
+	}
+
+	/** Set the winding rule for the path.
+	 * 
+	 * @param r is the winding rule for the path.
+	 */
+	public void setWindingRule(PathWindingRule r) {
+		assert(r!=null);
+		this.windingRule = r;
+	}
+
+	/** Add the elements replied by the iterator into this path.
+	 * 
+	 * @param iterator
+	 */
+	public void add(Iterator<PathElement2f> iterator) {
+		PathElement2f element;
+		while (iterator.hasNext()) {
+			element = iterator.next();
+			switch(element.type) {
+			case MOVE_TO:
+				moveTo(element.toX, element.toY);
+				break;
+			case LINE_TO:
+				lineTo(element.toX, element.toY);
+				break;
+			case QUAD_TO:
+				quadTo(element.ctrlX1, element.ctrlY1, element.toX, element.toY);
+				break;
+			case CURVE_TO:
+				curveTo(element.ctrlX1, element.ctrlY1, element.ctrlX2, element.ctrlY2, element.toX, element.toY);
+				break;
+			case CLOSE:
+				closePath();
+				break;
+			default:
+			}
+		}
+	}
+
+	private void ensureSlots(boolean needMove, int n) {
+		if (needMove && this.numTypes==0) {
+			throw new IllegalStateException("missing initial moveto in path definition"); //$NON-NLS-1$
+		}
+		if (this.types.length==this.numTypes) {
+			this.types = Arrays.copyOf(this.types, this.types.length+GROW_SIZE);
+		}
+		while ((this.numCoords+n)>=this.coords.length) {
+			this.coords = Arrays.copyOf(this.coords, this.coords.length+GROW_SIZE);
+		}
+	}
+
+	/**
+	 * Adds a point to the path by moving to the specified
+	 * coordinates specified in float precision.
+	 *
+	 * @param x the specified X coordinate
+	 * @param y the specified Y coordinate
+	 */
+	public void moveTo(float x, float y) {
+		if (this.numTypes>0 && this.types[this.numTypes-1]==PathElementType.MOVE_TO) {
+			this.coords[this.numCoords-2] = x;
+			this.coords[this.numCoords-1] = y;
+		}
+		else {
+			ensureSlots(false, 2);
+			this.types[this.numTypes++] = PathElementType.MOVE_TO;
+			this.coords[this.numCoords++] = x;
+			this.coords[this.numCoords++] = y;
+		}
+		this.bounds = null;
+	}
+
+	/**
+	 * Adds a point to the path by drawing a straight line from the
+	 * current coordinates to the new specified coordinates
+	 * specified in float precision.
+	 *
+	 * @param x the specified X coordinate
+	 * @param y the specified Y coordinate
+	 */
+	public void lineTo(float x, float y) {
+		ensureSlots(true, 2);
+		this.types[this.numTypes++] = PathElementType.LINE_TO;
+		this.coords[this.numCoords++] = x;
+		this.coords[this.numCoords++] = y;
+		this.isEmpty = null;
+		this.bounds = null;
+	}
+
+	/**
+	 * Adds a curved segment, defined by two new points, to the path by
+	 * drawing a Quadratic curve that intersects both the current
+	 * coordinates and the specified coordinates {@code (x2,y2)},
+	 * using the specified point {@code (x1,y1)} as a quadratic
+	 * parametric control point.
+	 * All coordinates are specified in float precision.
+	 *
+	 * @param x1 the X coordinate of the quadratic control point
+	 * @param y1 the Y coordinate of the quadratic control point
+	 * @param x2 the X coordinate of the final end point
+	 * @param y2 the Y coordinate of the final end point
+	 */
+	public void quadTo(float x1, float y1, float x2, float y2) {
+		ensureSlots(true, 4);
+		this.types[this.numTypes++] = PathElementType.QUAD_TO;
+		this.coords[this.numCoords++] = x1;
+		this.coords[this.numCoords++] = y1;
+		this.coords[this.numCoords++] = x2;
+		this.coords[this.numCoords++] = y2;
+		this.isEmpty = null;
+		this.bounds = null;
+	}
+
+	/**
+	 * Adds a curved segment, defined by three new points, to the path by
+	 * drawing a B&eacute;zier curve that intersects both the current
+	 * coordinates and the specified coordinates {@code (x3,y3)},
+	 * using the specified points {@code (x1,y1)} and {@code (x2,y2)} as
+	 * B&eacute;zier control points.
+	 * All coordinates are specified in float precision.
+	 *
+	 * @param x1 the X coordinate of the first B&eacute;zier control point
+	 * @param y1 the Y coordinate of the first B&eacute;zier control point
+	 * @param x2 the X coordinate of the second B&eacute;zier control point
+	 * @param y2 the Y coordinate of the second B&eacute;zier control point
+	 * @param x3 the X coordinate of the final end point
+	 * @param y3 the Y coordinate of the final end point
+	 */
+	public void curveTo(float x1, float y1,
+			float x2, float y2,
+			float x3, float y3) {
+		ensureSlots(true, 6);
+		this.types[this.numTypes++] = PathElementType.CURVE_TO;
+		this.coords[this.numCoords++] = x1;
+		this.coords[this.numCoords++] = y1;
+		this.coords[this.numCoords++] = x2;
+		this.coords[this.numCoords++] = y2;
+		this.coords[this.numCoords++] = x3;
+		this.coords[this.numCoords++] = y3;
+		this.isEmpty = null;
+		this.bounds = null;
+	}
+
+	/**
+	 * Closes the current subpath by drawing a straight line back to
+	 * the coordinates of the last {@code moveTo}.  If the path is already
+	 * closed or if the previous coordinates are for a {@code moveTo}
+	 * then this method has no effect.
+	 */
+	public void closePath() {
+		if (this.numTypes<=0 ||
+			(this.types[this.numTypes-1]!=PathElementType.CLOSE
+			&&this.types[this.numTypes-1]!=PathElementType.MOVE_TO)) {
+			ensureSlots(true, 0);
+			this.types[this.numTypes++] = PathElementType.CLOSE;
+		}
+	}
+
+	/** Replies an iterator on the path elements.
+	 * <p>
+	 * Only {@link PathElementType#MOVE_TO},
+	 * {@link PathElementType#LINE_TO}, and 
+	 * {@link PathElementType#CLOSE} types are returned by the iterator.
+	 * <p>
+	 * The amount of subdivision of the curved segments is controlled by the 
+	 * flatness parameter, which specifies the maximum distance that any point 
+	 * on the unflattened transformed curve can deviate from the returned
+	 * flattened path segments. Note that a limit on the accuracy of the
+	 * flattened path might be silently imposed, causing very small flattening
+	 * parameters to be treated as larger values. This limit, if there is one,
+	 * is defined by the particular implementation that is used.
+	 * <p>
+	 * The iterator for this class is not multi-threaded safe.
+	 * 
+	 * @param flatness is the maximum distance that the line segments used to approximate
+	 * the curved segments are allowed to deviate from any point on the original curve.
+	 * @return an iterator on the path elements.
+	 */
+	public PathIterator2f getPathIterator(float flatness) {
+		return new FlatteningPathIterator(getWindingRule(), getPathIterator(null), flatness, 10);
+	}
+
+	/** Replies an iterator on the path elements.
+	 * <p>
+	 * Only {@link PathElementType#MOVE_TO},
+	 * {@link PathElementType#LINE_TO}, and 
+	 * {@link PathElementType#CLOSE} types are returned by the iterator.
+	 * <p>
+	 * The amount of subdivision of the curved segments is controlled by the 
+	 * flatness parameter, which specifies the maximum distance that any point 
+	 * on the unflattened transformed curve can deviate from the returned
+	 * flattened path segments. Note that a limit on the accuracy of the
+	 * flattened path might be silently imposed, causing very small flattening
+	 * parameters to be treated as larger values. This limit, if there is one,
+	 * is defined by the particular implementation that is used.
+	 * <p>
+	 * The iterator for this class is not multi-threaded safe.
+	 *
+	 * @param transform is an optional affine Transform2D to be applied to the
+	 * coordinates as they are returned in the iteration, or <code>null</code> if 
+	 * untransformed coordinates are desired.
+	 * @param flatness is the maximum distance that the line segments used to approximate
+	 * the curved segments are allowed to deviate from any point on the original curve.
+	 * @return an iterator on the path elements.
+	 */
+	public PathIterator2f getPathIterator(Transform2D transform, float flatness) {
+		return new FlatteningPathIterator(getWindingRule(), getPathIterator(transform), flatness, 10);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public PathIterator2f getPathIterator(Transform2D transform) {
+		if (transform == null) {
+			return new CopyPathIterator();
+		}
+		return new TransformPathIterator(transform);
+	}
+
+	/** Transform the current path.
+	 * This function changes the current path.
+	 * 
+	 * @param transform is the affine transformation to apply.
+	 * @see #createTransformedShape(Transform2D)
+	 */
+	public void transform(Transform2D transform) {
+		if (transform!=null) {
+			Point2D p = new Point2f();
+			for(int i=0; i<this.numCoords;) {
+				p.set(this.coords[i], this.coords[i+1]);
+				transform.transform(p);
+				this.coords[i++] = p.getX();
+				this.coords[i++] = p.getY();
+			}
+			this.bounds = null;
+		}
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public void translate(float dx, float dy) {
+		for(int i=0; i<this.numCoords;) {
+			this.coords[i++] += dx;
+			this.coords[i++] += dy;
+		}
+		Rectangle2f bb = this.bounds==null ? null : this.bounds.get();
+		if (bb!=null) bb.translate(dx, dy);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Shape2f createTransformedShape(Transform2D transform) {
+		Path2f newPath = new Path2f(getWindingRule());
+		PathIterator2f pi = getPathIterator();
+		Point2f p = new Point2f();
+		Point2f t1 = new Point2f();
+		Point2f t2 = new Point2f();
+		PathElement2f e;
+		while (pi.hasNext()) {
+			e = pi.next();
+			switch(e.type) {
+			case MOVE_TO:
+				p.set(e.toX, e.toY);
+				transform.transform(p);
+				newPath.moveTo(p.getX(), p.getY());
+				break;
+			case LINE_TO:
+				p.set(e.toX, e.toY);
+				transform.transform(p);
+				newPath.lineTo(p.getX(), p.getY());
+				break;
+			case QUAD_TO:
+				t1.set(e.ctrlX1, e.ctrlY1);
+				transform.transform(t1);
+				p.set(e.toX, e.toY);
+				transform.transform(p);
+				newPath.quadTo(t1.getX(), t1.getY(), p.getX(), p.getY());
+				break;
+			case CURVE_TO:
+				t1.set(e.ctrlX1, e.ctrlY1);
+				transform.transform(t1);
+				t2.set(e.ctrlX2, e.ctrlY2);
+				transform.transform(t2);
+				p.set(e.toX, e.toY);
+				transform.transform(p);
+				newPath.curveTo(t1.getX(), t1.getY(), t2.getX(), t2.getY(), p.getX(), p.getY());
+				break;
+			case CLOSE:
+				newPath.closePath();
+				break;
+			default:
+			}
+		}
+		return newPath;
+	}
+
+	@Override
+	public float distanceSquared(Point2D p) {
+		Point2D c = getClosestPointTo(p);
+		return c.distanceSquared(p);
+	}
+
+	@Override
+	public float distanceL1(Point2D p) {
+		Point2D c = getClosestPointTo(p);
+		return c.distanceL1(p);
+	}
+
+	@Override
+	public float distanceLinf(Point2D p) {
+		Point2D c = getClosestPointTo(p);
+		return c.distanceLinf(p);
+	}
+
+	@Override
+	public boolean contains(float x, float y) {
+		return contains(getPathIterator(), x, y);
+	}
+
+	@Override
+	public boolean contains(Rectangle2f r) {
+		return contains(getPathIterator(),
+				r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight());
+	}
+
+	@Override
+	public boolean intersects(Rectangle2f s) {
+		// Copied from AWT API
+		if (s.isEmpty()) return false;
+		int mask = (this.windingRule == PathWindingRule.NON_ZERO ? -1 : 2);
+		int crossings = computeCrossingsFromRect(
+				getPathIterator(),
+				s.getMinX(), s.getMinY(), s.getMaxX(), s.getMaxY());
+		return (crossings == MathConstants.SHAPE_INTERSECTS ||
+				(crossings & mask) != 0);
+	}
+
+	@Override
+	public boolean intersects(Ellipse2f s) {
+		int mask = (this.windingRule == PathWindingRule.NON_ZERO ? -1 : 2);
+		int crossings = computeCrossingsFromEllipse(
+				getPathIterator(),
+				s.getMinX(), s.getMinY(), s.getWidth(), s.getHeight());
+		return (crossings == MathConstants.SHAPE_INTERSECTS ||
+				(crossings & mask) != 0);
+	}
+
+	@Override
+	public boolean intersects(Circle2f s) {
+		int mask = (this.windingRule == PathWindingRule.NON_ZERO ? -1 : 2);
+		int crossings = computeCrossingsFromCircle(
+				getPathIterator(),
+				s.getX(), s.getY(), s.getRadius());
+		return (crossings == MathConstants.SHAPE_INTERSECTS ||
+				(crossings & mask) != 0);
+	}
+
+	@Override
+	public boolean intersects(Segment2f s) {
+		int mask = (this.windingRule == PathWindingRule.NON_ZERO ? -1 : 2);
+		int crossings = computeCrossingsFromSegment(
+				getPathIterator(),
+				s.getX1(), s.getY1(), s.getX2(), s.getY2());
+		return (crossings == MathConstants.SHAPE_INTERSECTS ||
+				(crossings & mask) != 0);
+	}
+
+	@Override
+	public Rectangle2f toBoundingBox() {
+		Rectangle2f bb = this.bounds==null ? null : this.bounds.get();
+		if (bb==null) {
+			float xmin = Float.POSITIVE_INFINITY;
+			float ymin = Float.POSITIVE_INFINITY;
+			float xmax = Float.NEGATIVE_INFINITY;
+			float ymax = Float.NEGATIVE_INFINITY;
+			for(int i=0; i<this.numCoords; i+= 2) {
+				if (this.coords[i]<xmin) xmin = this.coords[i];
+				if (this.coords[i+1]<ymin) ymin = this.coords[i+1];
+				if (this.coords[i]>xmax) xmax = this.coords[i];
+				if (this.coords[i+1]>ymax) ymax = this.coords[i+1];
+			}
+			bb = new Rectangle2f();
+			bb.setFromCorners(xmin, ymin, xmax, ymax);
+			this.bounds = new SoftReference<Rectangle2f>(bb);
+		}
+		return bb;
+	}
+
+	@Override
+	public Point2D getClosestPointTo(Point2D p) {
+		Point2D closest = null;
+		float bestDist = Float.POSITIVE_INFINITY;
+		Point2D candidate;
+		PathIterator2f pi = getPathIterator(MathConstants.SPLINE_APPROXIMATION_RATIO);
+		PathElement2f pe;
+
+		int mask = (pi.getWindingRule() == PathWindingRule.NON_ZERO ? -1 : 1);
+		int crossings = 0;
+		boolean isClosed = false;
+		float moveX, moveY, currentX, currentY;
+		moveX = moveY = currentX = currentY = Float.NaN;
+		
+		while (pi.hasNext()) {
+			pe = pi.next();
+
+			candidate = null;
+
+			currentX = pe.toX;
+			currentY = pe.toY;
+
+			switch(pe.type) {
+			case MOVE_TO:
+				moveX = pe.toX;
+				moveY = pe.toY;
+				isClosed = false;
+				candidate = new Point2f(pe.toX, pe.toY);
+				break;
+			case LINE_TO:
+			{
+				isClosed = false;
+				float factor =  MathUtil.projectsPointOnLine(
+						p.getX(), p.getY(),
+						pe.fromX, pe.fromY, pe.toX, pe.toY);
+				factor = MathUtil.clamp(factor, 0f, 1f);
+				Vector2f v = new Vector2f(pe.toX, pe.toY);
+				v.sub(pe.fromX, pe.fromY);
+				v.scale(factor);
+				candidate = new Point2f(
+						pe.fromX + v.getX(),
+						pe.fromY + v.getY());
+				crossings += Segment2f.computeCrossingsFromPoint(
+						p.getX(), p.getY(),
+						pe.fromX, pe.fromY, pe.toX, pe.toY);
+				break;
+			}
+			case CLOSE:
+				isClosed = true;
+				if (!pe.isEmpty()) {
+					float factor =  MathUtil.projectsPointOnLine(
+							p.getX(), p.getY(),
+							pe.fromX, pe.fromY, pe.toX, pe.toY);
+					factor = MathUtil.clamp(factor, 0f, 1f);
+					Vector2f v = new Vector2f(pe.toX, pe.toY);
+					v.sub(pe.fromX, pe.fromY);
+					v.scale(factor);
+					candidate = new Point2f(
+							pe.fromX + v.getX(),
+							pe.fromY + v.getY());
+					crossings += Segment2f.computeCrossingsFromPoint(
+							p.getX(), p.getY(),
+							pe.fromX, pe.fromY, pe.toX, pe.toY);
+				}
+				break;
+			case QUAD_TO:
+			case CURVE_TO:
+			default:
+				throw new IllegalStateException();
+			}
+
+			if (candidate!=null) {
+				float d = p.distanceSquared(candidate);
+				if (d<bestDist) {
+					bestDist = d;
+					closest = candidate;
+				}
+			}
+		}
+		
+		if (!isClosed) {
+			crossings += Segment2f.computeCrossingsFromPoint(
+					p.getX(), p.getY(),
+					currentX, currentY,
+					moveX, moveY);
+		}
+		
+		if ((crossings & mask) != 0) return p;
+		return closest;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof Path2f) {
+			Path2f p = (Path2f)obj;
+			return (this.numCoords==p.numCoords
+					&&this.numTypes==p.numTypes
+					&&Arrays.equals(this.coords, p.coords)
+					&&Arrays.equals(this.types, p.types)
+					&&this.windingRule==p.windingRule);
+		}
+		return false;
+	}
+	
+	@Override
+	public int hashCode() {
+		long bits = 1L;
+		bits = 31L * bits + this.numCoords;
+		bits = 31L * bits + this.numTypes;
+		bits = 31L * bits + Arrays.hashCode(this.coords);
+		bits = 31L * bits + Arrays.hashCode(this.types);
+		bits = 31L * bits + this.windingRule.ordinal();
+		return (int) (bits ^ (bits >> 32));
+	}
+
+	/** Replies the coordinates of this path in an array of
+	 * single precision floating-point numbers.
+	 * 
+	 * @return the coordinates.
+	 */
+	public final float[] toFloatArray() {
+		return toFloatArray(null);
+	}
+
+	/** Replies the coordinates of this path in an array of
+	 * single precision floating-point numbers.
+	 * 
+	 * @param transform is the transformation to apply to all the coordinates.
+	 * @return the coordinates.
+	 */
+	public float[] toFloatArray(Transform2D transform) {
+		if (transform==null) {
+			return Arrays.copyOf(this.coords, this.numCoords);
+		}
+		Point2f p = new Point2f();
+		float[] clone = new float[this.numCoords];
+		for(int i=0; i<clone.length;) {
+			p.x = this.coords[i];
+			p.y = this.coords[i+1];
+			transform.transform(p);
+			clone[i++] = p.x;
+			clone[i++] = p.y;
+		}
+		return clone;
+	}
+
+	/** Replies the coordinates of this path in an array of
+	 * double precision floating-point numbers.
+	 * 
+	 * @return the coordinates.
+	 */
+	public final double[] toDoubleArray() {
+		return toDoubleArray(null);
+	}
+
+	/** Replies the coordinates of this path in an array of
+	 * double precision floating-point numbers.
+	 * 
+	 * @param transform is the transformation to apply to all the coordinates.
+	 * @return the coordinates.
+	 */
+	public double[] toDoubleArray(Transform2D transform) {
+		double[] clone = new double[this.numCoords];
+		if (transform==null) {
+			for(int i=0; i<this.numCoords; ++i) {
+				clone[i] = this.coords[i];
+			}
+		}
+		else {
+			Point2f p = new Point2f();
+			for(int i=0; i<clone.length;) {
+				p.x = this.coords[i];
+				p.y = this.coords[i+1];
+				transform.transform(p);
+				clone[i++] = p.x;
+				clone[i++] = p.y;
+			}
+		}
+		return clone;
+	}
+	
+	/** Replies the points of this path in an array.
+	 * 
+	 * @return the points.
+	 */
+	public final Point2D[] toPointArray() {
+		return toPointArray(null);
+	}
+
+	/** Replies the points of this path in an array.
+	 * 
+	 * @param transform is the transformation to apply to all the points.
+	 * @return the points.
+	 */
+	public Point2D[] toPointArray(Transform2D transform) {
+		Point2D[] clone = new Point2D[this.numCoords/2];
+		if (transform==null) {
+			for(int i=0, j=0; j<this.numCoords; ++i) {
+				clone[i] = new Point2f(
+						this.coords[j++],
+						this.coords[j++]);
+			}
+		}
+		else {
+			for(int i=0, j=0; j<clone.length; ++i) {
+				clone[i] = new Point2f(
+						this.coords[j++],
+						this.coords[j++]);
+				transform.transform(clone[i]);
+			}
+		}
+		return clone;
+	}
+
+	/** Replies the collection that is contains all the points of the path.
+	 * 
+	 * @return the point collection.
+	 */
+	public final Collection<Point2D> toCollection() {
+		return new PointCollection();
+	}
+
+	/** Replies the coordinate at the given index.
+	 * The index is in [0;{@link #size()}*2).
+	 *
+	 * @param index
+	 * @return the coordinate at the given index.
+	 */
+	public float getCoordAt(int index) {
+		return this.coords[index];
+	}
+	
+	/** Replies the point at the given index.
+	 * The index is in [0;{@link #size()}).
+	 *
+	 * @param index
+	 * @return the point at the given index.
+	 */
+	public Point2f getPointAt(int index) {
+		return new Point2f(
+				this.coords[index*2],
+				this.coords[index*2+1]);
+	}
+
+	/** Replies the number of points in the path.
+	 *
+	 * @return the number of points in the path.
+	 */
+	public int size() {
+		return this.numCoords/2;
+	}
+	
+	/** Replies if this path is empty.
+	 * The path is empty when there is no point inside, or
+	 * all the points are at the same coordinate, or
+	 * when the path does not represents a drawable path
+	 * (a path with a line or a curve).
+	 * 
+	 * @return <code>true</code> if the path does not contain
+	 * a coordinate; otherwise <code>false</code>.
+	 */
+	@Override
+	public boolean isEmpty() {
+		if (this.isEmpty==null) {
+			this.isEmpty = Boolean.TRUE;
+			PathIterator2f pi = getPathIterator();
+			PathElement2f pe;
+			while (this.isEmpty()==Boolean.TRUE && pi.hasNext()) {
+				pe = pi.next();
+				if (pe.isDrawable()) { 
+					this.isEmpty = Boolean.FALSE;
+				}
+			}
+		}
+		return this.isEmpty;
+	}
+	
+	/** Replies if the given points exists in the coordinates of this path.
+	 * 
+	 * @param p
+	 * @return <code>true</code> if the point is a control point of the path.
+	 */
+	boolean containsPoint(Point2D p) {
+		float x, y;
+		for(int i=0; i<this.numCoords;) {
+			x = this.coords[i++];
+			y = this.coords[i++];
+			if (x==p.getX() && y==p.getY()) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	
+	/** Remove the point with the given coordinates.
+	 * 
+	 * @param x
+	 * @param y
+	 * @return <code>true</code> if the point was removed; <code>false</code> otherwise.
+	 */
+	boolean remove(float x, float y) {
+		for(int i=0, j=0; i<this.numCoords && j<this.numTypes;) {
+			switch(this.types[j]) {
+			case MOVE_TO:
+			case LINE_TO:
+				if (x==this.coords[i] && y==this.coords[i+1]) {
+					this.numCoords -= 2;
+					--this.numTypes;
+					System.arraycopy(this.coords, i+2, this.coords, i, this.numCoords);
+					System.arraycopy(this.types, j+1, this.types, j, this.numTypes);
+					return true;
+				}
+				i += 2;
+				++j;
+				break;
+			case CURVE_TO:
+				if ((x==this.coords[i] && y==this.coords[i+1])
+					||(x==this.coords[i+2] && y==this.coords[i+3])
+					||(x==this.coords[i+4] && y==this.coords[i+5])) {
+					this.numCoords -= 6;
+					--this.numTypes;
+					System.arraycopy(this.coords, i+6, this.coords, i, this.numCoords);
+					System.arraycopy(this.types, j+1, this.types, j, this.numTypes);
+					return true;
+				}
+				i += 6;
+				++j;
+				break;
+			case QUAD_TO:
+				if ((x==this.coords[i] && y==this.coords[i+1])
+					||(x==this.coords[i+2] && y==this.coords[i+3])) {
+					this.numCoords -= 4;
+					--this.numTypes;
+					System.arraycopy(this.coords, i+4, this.coords, i, this.numCoords);
+					System.arraycopy(this.types, j+1, this.types, j, this.numTypes);
+					return true;
+				}
+				i += 4;
+				++j;
+				break;
+			case CLOSE:
+				++j;
+				break;
+			default:
+				break;
+			}
+		}
+		return false;
+	}
+	
+	/** Remove the last action.
+	 */
+	public void removeLast() {
+		if (this.numTypes>0) {
+			switch(this.types[this.numTypes-1]) {
+			case CLOSE:
+				// no coord to remove
+				break;
+			case MOVE_TO:
+			case LINE_TO:
+				this.numCoords -= 2;
+				break;
+			case CURVE_TO:
+				this.numCoords -= 6;
+				break;
+			case QUAD_TO:
+				this.numCoords -= 4;
+				break;
+			default:
+				throw new IllegalStateException();
+			}
+			--this.numTypes;
+			this.isEmpty = null;
+			this.bounds = null;
+		}
+	}
+
+	/** Change the coordinates of the last inserted point.
+	 * 
+	 * @param x
+	 * @param y
+	 */
+	public void setLastPoint(float x, float y) {
+		if (this.numCoords>=2) {
+			this.coords[this.numCoords-2] = x;
+			this.coords[this.numCoords-1] = y;
+			this.bounds = null;
+		}
+	}
+
+	/** A path iterator that does not transform the coordinates.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private class CopyPathIterator implements PathIterator2f {
+
+		private final Point2D p1 = new Point2f();
+		private final Point2D p2 = new Point2f();
+		private int iType = 0;
+		private int iCoord = 0;
+		private float movex, movey;
+
+		/**
+		 */
+		public CopyPathIterator() {
+			//
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.iType<Path2f.this.numTypes;
+		}
+
+		@Override
+		public PathElement2f next() {
+			int type = this.iType;
+			if (this.iType>=Path2f.this.numTypes) {
+				throw new NoSuchElementException();
+			}
+			PathElement2f element = null;
+			switch(Path2f.this.types[type]) {
+			case MOVE_TO:
+				if (this.iCoord+2>Path2f.this.numCoords) {
+					throw new NoSuchElementException();
+				}
+				this.movex = Path2f.this.coords[this.iCoord++];
+				this.movey = Path2f.this.coords[this.iCoord++];
+				this.p2.set(this.movex, this.movey);
+				element = new PathElement2f.MovePathElement2f(
+						this.p2.getX(), this.p2.getY());
+				break;
+			case LINE_TO:
+				if (this.iCoord+2>Path2f.this.numCoords) {
+					throw new NoSuchElementException();
+				}
+				this.p1.set(this.p2);
+				this.p2.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				element = new PathElement2f.LinePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.p2.getX(), this.p2.getY());
+				break;
+			case QUAD_TO:
+			{
+				if (this.iCoord+4>Path2f.this.numCoords) {
+					throw new NoSuchElementException();
+				}
+				this.p1.set(this.p2);
+				float ctrlx = Path2f.this.coords[this.iCoord++];
+				float ctrly = Path2f.this.coords[this.iCoord++];
+				this.p2.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				element = new PathElement2f.QuadPathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						ctrlx, ctrly,
+						this.p2.getX(), this.p2.getY());
+			}
+			break;
+			case CURVE_TO:
+			{
+				if (this.iCoord+6>Path2f.this.numCoords) {
+					throw new NoSuchElementException();
+				}
+				this.p1.set(this.p2);
+				float ctrlx1 = Path2f.this.coords[this.iCoord++];
+				float ctrly1 = Path2f.this.coords[this.iCoord++];
+				float ctrlx2 = Path2f.this.coords[this.iCoord++];
+				float ctrly2 = Path2f.this.coords[this.iCoord++];
+				this.p2.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				element = new PathElement2f.CurvePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						ctrlx1, ctrly1,
+						ctrlx2, ctrly2,
+						this.p2.getX(), this.p2.getY());
+			}
+			break;
+			case CLOSE:
+				this.p1.set(this.p2);
+				this.p2.set(this.movex, this.movey);
+				element = new PathElement2f.ClosePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.p2.getX(), this.p2.getY());
+				break;
+			default:
+			}
+			if (element==null)
+				throw new NoSuchElementException();
+			
+			++this.iType;
+			
+			return element;
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return Path2f.this.getWindingRule();
+		}
+
+	} // class CopyPathIterator
+
+	/** A path iterator that transforms the coordinates.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private class TransformPathIterator implements PathIterator2f {
+
+		private final Transform2D transform;
+		private final Point2D p1 = new Point2f();
+		private final Point2D p2 = new Point2f();
+		private final Point2D ptmp1 = new Point2f();
+		private final Point2D ptmp2 = new Point2f();
+		private int iType = 0;
+		private int iCoord = 0;
+		private float movex, movey;
+
+		/**
+		 * @param transform
+		 */
+		public TransformPathIterator(Transform2D transform) {
+			assert(transform!=null);
+			this.transform = transform;
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.iType<Path2f.this.numTypes;
+		}
+
+		@Override
+		public PathElement2f next() {
+			if (this.iType>=Path2f.this.numTypes) {
+				throw new NoSuchElementException();
+			}
+			PathElement2f element = null;
+			switch(Path2f.this.types[this.iType++]) {
+			case MOVE_TO:
+				this.movex = Path2f.this.coords[this.iCoord++];
+				this.movey = Path2f.this.coords[this.iCoord++];
+				this.p2.set(this.movex, this.movey);
+				this.transform.transform(this.p2);
+				element = new PathElement2f.MovePathElement2f(
+						this.p2.getX(), this.p2.getY());
+				break;
+			case LINE_TO:
+				this.p1.set(this.p2);
+				this.p2.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				this.transform.transform(this.p2);
+				element = new PathElement2f.LinePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.p2.getX(), this.p2.getY());
+				break;
+			case QUAD_TO:
+			{
+				this.p1.set(this.p2);
+				this.ptmp1.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				this.transform.transform(this.ptmp1);
+				this.p2.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				this.transform.transform(this.p2);
+				element = new PathElement2f.QuadPathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.ptmp1.getX(), this.ptmp1.getY(),
+						this.p2.getX(), this.p2.getY());
+			}
+			break;
+			case CURVE_TO:
+			{
+				this.p1.set(this.p2);
+				this.ptmp1.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				this.transform.transform(this.ptmp1);
+				this.ptmp2.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				this.transform.transform(this.ptmp2);
+				this.p2.set(
+						Path2f.this.coords[this.iCoord++],
+						Path2f.this.coords[this.iCoord++]);
+				this.transform.transform(this.p2);
+				element = new PathElement2f.CurvePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.ptmp1.getX(), this.ptmp1.getY(),
+						this.ptmp2.getX(), this.ptmp2.getY(),
+						this.p2.getX(), this.p2.getY());
+			}
+			break;
+			case CLOSE:
+				this.p1.set(this.p2);
+				this.p2.set(this.movex, this.movey);
+				this.transform.transform(this.p2);
+				element = new PathElement2f.ClosePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.p2.getX(), this.p2.getY());
+				break;
+			default:
+			}
+			if (element==null)
+				throw new NoSuchElementException();
+			return element;
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return Path2f.this.getWindingRule();
+		}
+
+	}  // class TransformPathIterator
+
+	/** A path iterator that is flattening the path.
+	 * This iterator was copied from AWT FlatteningPathIterator.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private static class FlatteningPathIterator implements PathIterator2f {
+
+		/** Winding rule of the path.
+		 */
+		private final PathWindingRule windingRule;
+
+		/** The source iterator.
+		 */
+		private final Iterator<PathElement2f> pathIterator;
+
+		/**
+		 * Square of the flatness parameter for testing against squared lengths.
+		 */
+		private final float squaredFlatness;
+
+		/**
+		 * Maximum number of recursion levels.
+		 */
+		private final int limit; 
+
+		/** The recursion level at which each curve being held in storage was generated.
+		 */
+		private int levels[];
+
+		/** The cache of interpolated coords.
+		 * Note that this must be long enough
+		 * to store a full cubic segment and
+		 * a relative cubic segment to avoid
+		 * aliasing when copying the coords
+		 * of a curve to the end of the array.
+		 * This is also serendipitously equal
+		 * to the size of a full quad segment
+		 * and 2 relative quad segments.
+		 */
+		private float hold[] = new float[14];
+
+		/** The index of the last curve segment being held for interpolation.
+		 */
+		private int holdEnd;
+
+		/**
+		 * The index of the curve segment that was last interpolated.  This
+		 * is the curve segment ready to be returned in the next call to
+		 * next().
+		 */
+		private int holdIndex;
+
+		/** The ending x of the last segment.
+		 */
+		private float currentX;
+
+		/** The ending y of the last segment.
+		 */
+		private float currentY;
+
+		/** The x of the last move segment.
+		 */
+		private float moveX;
+
+		/** The y of the last move segment.
+		 */
+		private float moveY;
+
+		/** The index of the entry in the
+		 * levels array of the curve segment
+		 * at the holdIndex
+		 */
+		private int levelIndex;
+
+		/** True when iteration is done.
+		 */
+		private boolean done;
+
+		/** The type of the path element.
+		 */
+		private PathElementType holdType;
+
+		/** The x of the last move segment replied by next.
+		 */
+		private float lastNextX;
+
+		/** The y of the last move segment replied by next.
+		 */
+		private float lastNextY;
+
+		/**
+		 * @param windingRule is the winding rule of the path.
+		 * @param pathIterator is the path iterator that may be used to initialize the path.
+		 * @param flatness the maximum allowable distance between the
+		 * control points and the flattened curve
+		 * @param limit the maximum number of recursive subdivisions
+		 * allowed for any curved segment
+		 */
+		public FlatteningPathIterator(PathWindingRule windingRule, Iterator<PathElement2f> pathIterator, float flatness, int limit) {
+			assert(windingRule!=null);
+			assert(flatness>=0f);
+			assert(limit>=0);
+			this.windingRule = windingRule;
+			this.pathIterator = pathIterator;
+			this.squaredFlatness = flatness * flatness;
+			this.limit = limit;
+			this.levels = new int[limit + 1];
+			searchNext();
+		}
+
+		/**
+		 * Ensures that the hold array can hold up to (want) more values.
+		 * It is currently holding (hold.length - holdIndex) values.
+		 */
+		private void ensureHoldCapacity(int want) {
+			if (this.holdIndex - want < 0) {
+				int have = this.hold.length - this.holdIndex;
+				int newsize = this.hold.length + GROW_SIZE;
+				float newhold[] = new float[newsize];
+				System.arraycopy(this.hold, this.holdIndex,
+						newhold, this.holdIndex + GROW_SIZE,
+						have);
+				this.hold = newhold;
+				this.holdIndex += GROW_SIZE;
+				this.holdEnd += GROW_SIZE;
+			}
+		}
+
+		/**
+		 * Returns the square of the flatness, or maximum distance of a
+		 * control point from the line connecting the end points, of the
+		 * quadratic curve specified by the control points stored in the
+		 * indicated array at the indicated index.
+		 * @param coords an array containing coordinate values
+		 * @param offset the index into <code>coords</code> from which to
+		 *          to start getting the values from the array
+		 * @return the flatness of the quadratic curve that is defined by the
+		 *          values in the specified array at the specified index.
+		 */
+		private static float getQuadSquaredFlatness(float coords[], int offset) {
+			return MathUtil.distanceSquaredPointToLine(
+					coords[offset + 2], coords[offset + 3],
+					coords[offset + 0], coords[offset + 1],
+					coords[offset + 4], coords[offset + 5]);
+		}
+
+		/**
+		 * Subdivides the quadratic curve specified by the coordinates
+		 * stored in the <code>src</code> array at indices
+		 * <code>srcoff</code> through <code>srcoff</code>&nbsp;+&nbsp;5
+		 * and stores the resulting two subdivided curves into the two
+		 * result arrays at the corresponding indices.
+		 * Either or both of the <code>left</code> and <code>right</code>
+		 * arrays can be <code>null</code> or a reference to the same array
+		 * and offset as the <code>src</code> array.
+		 * Note that the last point in the first subdivided curve is the
+		 * same as the first point in the second subdivided curve.  Thus,
+		 * it is possible to pass the same array for <code>left</code> and
+		 * <code>right</code> and to use offsets such that
+		 * <code>rightoff</code> equals <code>leftoff</code> + 4 in order
+		 * to avoid allocating extra storage for this common point.
+		 * @param src the array holding the coordinates for the source curve
+		 * @param srcoff the offset into the array of the beginning of the
+		 * the 6 source coordinates
+		 * @param left the array for storing the coordinates for the first
+		 * half of the subdivided curve
+		 * @param leftoff the offset into the array of the beginning of the
+		 * the 6 left coordinates
+		 * @param right the array for storing the coordinates for the second
+		 * half of the subdivided curve
+		 * @param rightoff the offset into the array of the beginning of the
+		 * the 6 right coordinates
+		 */
+		private static void subdivideQuad(float src[], int srcoff,
+				float left[], int leftoff,
+				float right[], int rightoff) {
+			float x1 = src[srcoff + 0];
+			float y1 = src[srcoff + 1];
+			float ctrlx = src[srcoff + 2];
+			float ctrly = src[srcoff + 3];
+			float x2 = src[srcoff + 4];
+			float y2 = src[srcoff + 5];
+			if (left != null) {
+				left[leftoff + 0] = x1;
+				left[leftoff + 1] = y1;
+			}
+			if (right != null) {
+				right[rightoff + 4] = x2;
+				right[rightoff + 5] = y2;
+			}
+			x1 = (x1 + ctrlx) / 2f;
+			y1 = (y1 + ctrly) / 2f;
+			x2 = (x2 + ctrlx) / 2f;
+			y2 = (y2 + ctrly) / 2f;
+			ctrlx = (x1 + x2) / 2f;
+			ctrly = (y1 + y2) / 2f;
+			if (left != null) {
+				left[leftoff + 2] = x1;
+				left[leftoff + 3] = y1;
+				left[leftoff + 4] = ctrlx;
+				left[leftoff + 5] = ctrly;
+			}
+			if (right != null) {
+				right[rightoff + 0] = ctrlx;
+				right[rightoff + 1] = ctrly;
+				right[rightoff + 2] = x2;
+				right[rightoff + 3] = y2;
+			}
+		}
+
+		/**
+		 * Returns the square of the flatness of the cubic curve specified
+		 * by the control points stored in the indicated array at the
+		 * indicated index. The flatness is the maximum distance
+		 * of a control point from the line connecting the end points.
+		 * @param coords an array containing coordinates
+		 * @param offset the index of <code>coords</code> from which to begin
+		 *          getting the end points and control points of the curve
+		 * @return the square of the flatness of the <code>CubicCurve2D</code>
+		 *          specified by the coordinates in <code>coords</code> at
+		 *          the specified offset.
+		 */
+		private static float getCurveSquaredFlatness(float coords[], int offset) {
+			return Math.max(
+					MathUtil.distanceSquaredPointToSegment(
+							coords[offset + 0],
+							coords[offset + 1],
+							coords[offset + 6],
+							coords[offset + 7],
+							coords[offset + 2],
+							coords[offset + 3]),
+							MathUtil.distanceSquaredPointToSegment(
+									coords[offset + 0],
+									coords[offset + 1],
+									coords[offset + 6],
+									coords[offset + 7],
+									coords[offset + 4], coords[offset + 5]));
+		}
+
+		/**
+		 * Subdivides the cubic curve specified by the coordinates
+		 * stored in the <code>src</code> array at indices <code>srcoff</code>
+		 * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
+		 * resulting two subdivided curves into the two result arrays at the
+		 * corresponding indices.
+		 * Either or both of the <code>left</code> and <code>right</code>
+		 * arrays may be <code>null</code> or a reference to the same array
+		 * as the <code>src</code> array.
+		 * Note that the last point in the first subdivided curve is the
+		 * same as the first point in the second subdivided curve. Thus,
+		 * it is possible to pass the same array for <code>left</code>
+		 * and <code>right</code> and to use offsets, such as <code>rightoff</code>
+		 * equals (<code>leftoff</code> + 6), in order
+		 * to avoid allocating extra storage for this common point.
+		 * @param src the array holding the coordinates for the source curve
+		 * @param srcoff the offset into the array of the beginning of the
+		 * the 6 source coordinates
+		 * @param left the array for storing the coordinates for the first
+		 * half of the subdivided curve
+		 * @param leftoff the offset into the array of the beginning of the
+		 * the 6 left coordinates
+		 * @param right the array for storing the coordinates for the second
+		 * half of the subdivided curve
+		 * @param rightoff the offset into the array of the beginning of the
+		 * the 6 right coordinates
+		 */
+		private static void subdivideCurve(
+				float src[], int srcoff,
+				float left[], int leftoff,
+				float right[], int rightoff) {
+			float x1 = src[srcoff + 0];
+			float y1 = src[srcoff + 1];
+			float ctrlx1 = src[srcoff + 2];
+			float ctrly1 = src[srcoff + 3];
+			float ctrlx2 = src[srcoff + 4];
+			float ctrly2 = src[srcoff + 5];
+			float x2 = src[srcoff + 6];
+			float y2 = src[srcoff + 7];
+			if (left != null) {
+				left[leftoff + 0] = x1;
+				left[leftoff + 1] = y1;
+			}
+			if (right != null) {
+				right[rightoff + 6] = x2;
+				right[rightoff + 7] = y2;
+			}
+			x1 = (x1 + ctrlx1) / 2f;
+			y1 = (y1 + ctrly1) / 2f;
+			x2 = (x2 + ctrlx2) / 2f;
+			y2 = (y2 + ctrly2) / 2f;
+			float centerx = (ctrlx1 + ctrlx2) / 2f;
+			float centery = (ctrly1 + ctrly2) / 2f;
+			ctrlx1 = (x1 + centerx) / 2f;
+			ctrly1 = (y1 + centery) / 2f;
+			ctrlx2 = (x2 + centerx) / 2f;
+			ctrly2 = (y2 + centery) / 2f;
+			centerx = (ctrlx1 + ctrlx2) / 2f;
+			centery = (ctrly1 + ctrly2) / 2f;
+			if (left != null) {
+				left[leftoff + 2] = x1;
+				left[leftoff + 3] = y1;
+				left[leftoff + 4] = ctrlx1;
+				left[leftoff + 5] = ctrly1;
+				left[leftoff + 6] = centerx;
+				left[leftoff + 7] = centery;
+			}
+			if (right != null) {
+				right[rightoff + 0] = centerx;
+				right[rightoff + 1] = centery;
+				right[rightoff + 2] = ctrlx2;
+				right[rightoff + 3] = ctrly2;
+				right[rightoff + 4] = x2;
+				right[rightoff + 5] = y2;
+			}
+		}
+
+		private void searchNext() {
+			int level;
+
+			if (this.holdIndex >= this.holdEnd) {
+				if (!this.pathIterator.hasNext()) {
+					this.done = true;
+					return;
+				}
+				PathElement2f pathElement = this.pathIterator.next();
+				this.holdType = pathElement.type;
+				pathElement.toArray(this.hold);
+				this.levelIndex = 0;
+				this.levels[0] = 0;
+			}
+
+			switch (this.holdType) {
+			case MOVE_TO:
+			case LINE_TO:
+				this.currentX = this.hold[0];
+				this.currentY = this.hold[1];
+				if (this.holdType == PathElementType.MOVE_TO) {
+					this.moveX = this.currentX;
+					this.moveY = this.currentY;
+				}
+				this.holdIndex = 0;
+				this.holdEnd = 0;
+				break;
+			case CLOSE:
+				this.currentX = this.moveX;
+				this.currentY = this.moveY;
+				this.holdIndex = 0;
+				this.holdEnd = 0;
+				break;
+			case QUAD_TO:
+				if (this.holdIndex >= this.holdEnd) {
+					// Move the coordinates to the end of the array.
+					this.holdIndex = this.hold.length - 6;
+					this.holdEnd = this.hold.length - 2;
+					this.hold[this.holdIndex + 0] = this.currentX;
+					this.hold[this.holdIndex + 1] = this.currentY;
+					this.hold[this.holdIndex + 2] = this.hold[0];
+					this.hold[this.holdIndex + 3] = this.hold[1];
+					this.hold[this.holdIndex + 4] = this.currentX = this.hold[2];
+					this.hold[this.holdIndex + 5] = this.currentY = this.hold[3];
+				}
+
+				level = this.levels[this.levelIndex];
+				while (level < this.limit) {
+					if (getQuadSquaredFlatness(this.hold, this.holdIndex) < this.squaredFlatness) {
+						break;
+					}
+
+					ensureHoldCapacity(4);
+					subdivideQuad(
+							this.hold, this.holdIndex,
+							this.hold, this.holdIndex - 4,
+							this.hold, this.holdIndex);
+					this.holdIndex -= 4;
+
+					// Now that we have subdivided, we have constructed
+					// two curves of one depth lower than the original
+					// curve.  One of those curves is in the place of
+					// the former curve and one of them is in the next
+					// set of held coordinate slots.  We now set both
+					// curves level values to the next higher level.
+					level++;
+					this.levels[this.levelIndex] = level;
+					this.levelIndex++;
+					this.levels[this.levelIndex] = level;
+				}
+
+				// This curve segment is flat enough, or it is too deep
+				// in recursion levels to try to flatten any more.  The
+				// two coordinates at holdIndex+4 and holdIndex+5 now
+				// contain the endpoint of the curve which can be the
+				// endpoint of an approximating line segment.
+				this.holdIndex += 4;
+				this.levelIndex--;
+				break;
+			case CURVE_TO:
+				if (this.holdIndex >= this.holdEnd) {
+					// Move the coordinates to the end of the array.
+					this.holdIndex = this.hold.length - 8;
+					this.holdEnd = this.hold.length - 2;
+					this.hold[this.holdIndex + 0] = this.currentX;
+					this.hold[this.holdIndex + 1] = this.currentY;
+					this.hold[this.holdIndex + 2] = this.hold[0];
+					this.hold[this.holdIndex + 3] = this.hold[1];
+					this.hold[this.holdIndex + 4] = this.hold[2];
+					this.hold[this.holdIndex + 5] = this.hold[3];
+					this.hold[this.holdIndex + 6] = this.currentX = this.hold[4];
+					this.hold[this.holdIndex + 7] = this.currentY = this.hold[5];
+				}
+
+				level = this.levels[this.levelIndex];
+				while (level < this.limit) {
+					if (getCurveSquaredFlatness(this.hold,this. holdIndex) < this.squaredFlatness) {
+						break;
+					}
+
+					ensureHoldCapacity(6);
+					subdivideCurve(
+							this.hold, this.holdIndex,
+							this.hold, this.holdIndex - 6,
+							this.hold, this.holdIndex);
+					this.holdIndex -= 6;
+
+					// Now that we have subdivided, we have constructed
+					// two curves of one depth lower than the original
+					// curve.  One of those curves is in the place of
+					// the former curve and one of them is in the next
+					// set of held coordinate slots.  We now set both
+					// curves level values to the next higher level.
+					level++;
+					this.levels[this.levelIndex] = level;
+					this.levelIndex++;
+					this.levels[this.levelIndex] = level;
+				}
+
+				// This curve segment is flat enough, or it is too deep
+				// in recursion levels to try to flatten any more.  The
+				// two coordinates at holdIndex+6 and holdIndex+7 now
+				// contain the endpoint of the curve which can be the
+				// endpoint of an approximating line segment.
+				this.holdIndex += 6;
+				this.levelIndex--;
+				break;
+			default:
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			return !this.done;
+		}
+
+		@Override
+		public PathElement2f next() {
+			if (this.done) {
+				throw new NoSuchElementException("flattening iterator out of bounds"); //$NON-NLS-1$
+			}
+
+			PathElement2f element;
+			PathElementType type = this.holdType;
+			if (type!=PathElementType.CLOSE) {
+				float x = this.hold[this.holdIndex + 0];
+				float y = this.hold[this.holdIndex + 1];
+				if (type == PathElementType.MOVE_TO) {
+					element = new PathElement2f.MovePathElement2f(x, y);
+				}
+				else {
+					element = new PathElement2f.LinePathElement2f(
+							this.lastNextX, this.lastNextY,
+							x, y);
+				}
+				this.lastNextX = x;
+				this.lastNextY = y;
+			}
+			else {
+				element = new PathElement2f.ClosePathElement2f(
+						this.lastNextX, this.lastNextY,
+						this.moveX, this.moveY);
+				this.lastNextX = this.moveX;
+				this.lastNextY = this.moveY;
+			}
+
+			searchNext();
+
+			return element;
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return this.windingRule;
+		}
+
+	} // class FlatteningPathIterator
+
+	/** An collection of the points of the path.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private class PointCollection implements Collection<Point2D> {
+
+		/**
+		 */
+		public PointCollection() {
+			//
+		}
+
+		@Override
+		public int size() {
+			return Path2f.this.size();
+		}
+
+		@Override
+		public boolean isEmpty() {
+			return Path2f.this.size()<=0;
+		}
+
+		@Override
+		public boolean contains(Object o) {
+			if (o instanceof Point2D) {
+				return Path2f.this.containsPoint((Point2D)o);
+			}
+			return false;
+		}
+
+		@Override
+		public Iterator<Point2D> iterator() {
+			return new PointIterator();
+		}
+
+		@Override
+		public Object[] toArray() {
+			return Path2f.this.toPointArray();
+		}
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public <T> T[] toArray(T[] a) {
+			Iterator<Point2D> iterator = new PointIterator();
+			for(int i=0; i<a.length && iterator.hasNext(); ++i) {
+				a[i] = (T)iterator.next();
+			}
+			return a;
+		}
+
+		@Override
+		public boolean add(Point2D e) {
+			if (e!=null) {
+				if (Path2f.this.size()==0) {
+					Path2f.this.moveTo(e.getX(), e.getY());
+				}
+				else {
+					Path2f.this.lineTo(e.getX(), e.getY());
+				}
+				return true;
+			}
+			return false;
+		}
+
+		@Override
+		public boolean remove(Object o) {
+			if (o instanceof Point2D) {
+				Point2D p = (Point2D)o;
+				return Path2f.this.remove(p.getX(), p.getY());
+			}
+			return false;
+		}
+
+		@Override
+		public boolean containsAll(Collection<?> c) {
+			for(Object obj : c) {
+				if ((!(obj instanceof Point2D))
+					||(!Path2f.this.containsPoint((Point2D)obj))) {
+					return false;
+				}
+			}
+			return true;
+		}
+
+		@Override
+		public boolean addAll(Collection<? extends Point2D> c) {
+			boolean changed = false;
+			for(Point2D pts : c) {
+				if (add(pts)) {
+					changed = true;
+				}
+			}
+			return changed;
+		}
+
+		@Override
+		public boolean removeAll(Collection<?> c) {
+			boolean changed = false;
+			for(Object obj : c) {
+				if (obj instanceof Point2D) {
+					Point2D pts = (Point2D)obj;
+					if (Path2f.this.remove(pts.getX(), pts.getY())) {
+						changed = true;
+					}
+				}
+			}
+			return changed;
+		}
+
+		@Override
+		public boolean retainAll(Collection<?> c) {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public void clear() {
+			Path2f.this.clear();
+		}
+		
+	} // class PointCollection
+	
+	/** Iterator on the points of the path.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private class PointIterator implements Iterator<Point2D> {
+
+		private int index = 0;
+		private Point2D lastReplied = null;
+		
+		/**
+		 */
+		public PointIterator() {
+			//
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.index<Path2f.this.size();
+		}
+
+		@Override
+		public Point2D next() {
+			try {
+				this.lastReplied = Path2f.this.getPointAt(this.index++);
+				return this.lastReplied;
+			}
+			catch(Throwable _) {
+				throw new NoSuchElementException();
+			}
+		}
+
+		@Override
+		public void remove() {
+			Point2D p = this.lastReplied;
+			this.lastReplied = null;
+			if (p==null)
+				throw new NoSuchElementException();
+			Path2f.this.remove(p.getX(), p.getY());
+		}
+		
+	}
+	
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathElement2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathElement2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathElement2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,443 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2005-09 Stephane GALLAND.
+ * Copyright (C) 2012 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import java.io.Serializable;
+
+import org.arakhne.afc.math.generic.PathElementType;
+
+/** An element of the path.
+ *
+ * @author $Author: galland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public abstract class PathElement2f implements Serializable {
+	
+	private static final long serialVersionUID = 8963281073370254033L;
+	
+	/** Create an instance of path element.
+	 * 
+	 * @param type is the type of the new element.
+	 * @param lastX is the coordinate of the last point.
+	 * @param lastY is the coordinate of the last point.
+	 * @param coords are the coordinates.
+	 * @return the instance of path element.
+	 */
+	public static PathElement2f newInstance(PathElementType type, float lastX, float lastY, float[] coords) {
+		switch(type) {
+		case MOVE_TO:
+			return new MovePathElement2f(coords[0], coords[1]);
+		case LINE_TO:
+			return new LinePathElement2f(lastX, lastY, coords[0], coords[1]);
+		case QUAD_TO:
+			return new QuadPathElement2f(lastX, lastY, coords[0], coords[1], coords[2], coords[3]);
+		case CURVE_TO:
+			return new CurvePathElement2f(lastX, lastY, coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
+		case CLOSE:
+			return new ClosePathElement2f(lastX, lastY, coords[0], coords[1]);
+		default:
+		}
+		throw new IllegalArgumentException();
+	}
+	
+	/** Type of the path element.
+	 */
+	public final PathElementType type;
+	
+	/** Source point.
+	 */
+	public final float fromX;
+	
+	/** Source point.
+	 */
+	public final float fromY;
+
+	/** Target point.
+	 */
+	public final float toX;
+	
+	/** Target point.
+	 */
+	public final float toY;
+
+	/** First control point.
+	 */
+	public final float ctrlX1;
+	
+	/** First control point.
+	 */
+	public final float ctrlY1;
+
+	/** Second control point.
+	 */
+	public final float ctrlX2;
+	
+	/** Second control point.
+	 */
+	public final float ctrlY2;
+
+	/**
+	 * @param type is the type of the element.
+	 * @param fromx is the source point.
+	 * @param fromy is the source point.
+	 * @param ctrlx1 is the first control point.
+	 * @param ctrly1 is the first control point.
+	 * @param ctrlx2 is the first control point.
+	 * @param ctrly2 is the first control point.
+	 * @param tox is the target point.
+	 * @param toy is the target point.
+	 */
+	public PathElement2f(PathElementType type, float fromx, float fromy, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float tox, float toy) {
+		assert(type!=null);
+		this.type = type;
+		this.fromX = fromx;
+		this.fromY = fromy;
+		this.ctrlX1 = ctrlx1;
+		this.ctrlY1 = ctrly1;
+		this.ctrlX2 = ctrlx2;
+		this.ctrlY2 = ctrly2;
+		this.toX = tox;
+		this.toY = toy;
+	}
+
+	/** Replies if the element is empty, ie. the points are the same.
+	 * 
+	 * @return <code>true</code> if the points are
+	 * the same; otherwise <code>false</code>.
+	 */
+	public abstract boolean isEmpty();
+	
+	/** Replies if the element is not empty and its drawable.
+	 * Only the path elements that may produce pixels on the screen
+	 * must reply <code>true</code> in this function.
+	 * 
+	 * @return <code>true</code> if the path element
+	 * is drawable; otherwise <code>false</code>.
+	 */
+	public abstract boolean isDrawable();
+
+	/** Copy the coords into the given array, except the source point.
+	 * 
+	 * @param array
+	 */
+	public abstract void toArray(float[] array);
+
+	/** Copy the coords into an array, except the source point.
+	 * 
+	 * @return the array of the points, except the source point.
+	 */
+	public abstract float[] toArray();
+
+	/** An element of the path that represents a <code>MOVE_TO</code>.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public static class MovePathElement2f extends PathElement2f {
+		
+		private static final long serialVersionUID = -5596181248741970433L;
+
+		/**
+		 * @param x
+		 * @param y
+		 */
+		public MovePathElement2f(float x, float y) {
+			super(PathElementType.MOVE_TO,
+					Float.NaN, Float.NaN,
+					Float.NaN, Float.NaN,
+					Float.NaN, Float.NaN,
+					x, y);
+		}
+
+		@Override
+		public boolean isEmpty() {
+			return (this.fromX==this.toX) && (this.fromY==this.toY);
+		}
+
+		@Override
+		public boolean isDrawable() {
+			return false;
+		}
+		
+		@Override
+		public void toArray(float[] array) {
+			array[0] = this.toX;
+			array[1] = this.toY;
+		}
+		
+		@Override
+		public float[] toArray() {
+			return new float[] {this.toX, this.toY};
+		}
+
+		@Override
+		public String toString() {
+			return "MOVE("+ //$NON-NLS-1$
+					this.toX+"x"+ //$NON-NLS-1$
+					this.toY+")"; //$NON-NLS-1$
+		}
+
+	}
+	
+	/** An element of the path that represents a <code>LINE_TO</code>.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public static class LinePathElement2f extends PathElement2f {
+		
+		private static final long serialVersionUID = -5878571187312098882L;
+
+		/**
+		 * @param fromx
+		 * @param fromy
+		 * @param tox
+		 * @param toy
+		 */
+		public LinePathElement2f(float fromx, float fromy, float tox, float toy) {
+			super(PathElementType.LINE_TO,
+					fromx, fromy,
+					Float.NaN, Float.NaN,
+					Float.NaN, Float.NaN,
+					tox, toy);
+		}
+		
+		@Override
+		public boolean isEmpty() {
+			return (this.fromX==this.toX) && (this.fromY==this.toY);
+		}
+
+		@Override
+		public boolean isDrawable() {
+			return !isEmpty();
+		}
+
+		@Override
+		public void toArray(float[] array) {
+			array[0] = this.toX;
+			array[1] = this.toY;
+		}
+		
+		@Override
+		public float[] toArray() {
+			return new float[] {this.toX, this.toY};
+		}
+
+		@Override
+		public String toString() {
+			return "LINE("+ //$NON-NLS-1$
+					this.toX+"x"+ //$NON-NLS-1$
+					this.toY+")"; //$NON-NLS-1$
+		}
+
+	}
+	
+	/** An element of the path that represents a <code>QUAD_TO</code>.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public static class QuadPathElement2f extends PathElement2f {
+		
+		private static final long serialVersionUID = 5641358330446739160L;
+
+		/**
+		 * @param fromx
+		 * @param fromy
+		 * @param ctrlx
+		 * @param ctrly
+		 * @param tox
+		 * @param toy
+		 */
+		public QuadPathElement2f(float fromx, float fromy, float ctrlx, float ctrly, float tox, float toy) {
+			super(PathElementType.QUAD_TO,
+					fromx, fromy,
+					ctrlx, ctrly,
+					Float.NaN, Float.NaN,
+					tox, toy);
+		}
+		
+		@Override
+		public boolean isEmpty() {
+			return (this.fromX==this.toX) && (this.fromY==this.toY) &&
+					(this.ctrlX1==this.toX) && (this.ctrlY1==this.toY);
+		}
+
+		@Override
+		public boolean isDrawable() {
+			return !isEmpty();
+		}
+
+		@Override
+		public void toArray(float[] array) {
+			array[0] = this.ctrlX1;
+			array[1] = this.ctrlY1;
+			array[2] = this.toX;
+			array[3] = this.toY;
+		}
+		
+		@Override
+		public float[] toArray() {
+			return new float[] {this.ctrlX1, this.ctrlY1, this.toX, this.toY};
+		}
+		
+		@Override
+		public String toString() {
+			return "QUAD("+ //$NON-NLS-1$
+					this.ctrlX1+"x"+ //$NON-NLS-1$
+					this.ctrlY1+"|"+ //$NON-NLS-1$
+					this.toX+"x"+ //$NON-NLS-1$
+					this.toY+")"; //$NON-NLS-1$
+		}
+
+	}
+
+	/** An element of the path that represents a <code>CURVE_TO</code>.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public static class CurvePathElement2f extends PathElement2f {
+		
+		private static final long serialVersionUID = -1449309552719221756L;
+
+		/**
+		 * @param fromx
+		 * @param fromy
+		 * @param ctrlx1
+		 * @param ctrly1
+		 * @param ctrlx2
+		 * @param ctrly2
+		 * @param tox
+		 * @param toy
+		 */
+		public CurvePathElement2f(float fromx, float fromy, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float tox, float toy) {
+			super(PathElementType.CURVE_TO,
+					fromx, fromy,
+					ctrlx1, ctrly1,
+					ctrlx2, ctrly2,
+					tox, toy);
+		}
+		
+		@Override
+		public boolean isEmpty() {
+			return (this.fromX==this.toX) && (this.fromY==this.toY) &&
+					(this.ctrlX1==this.toX) && (this.ctrlY1==this.toY) &&
+					(this.ctrlX2==this.toX) && (this.ctrlY2==this.toY);
+		}
+
+		@Override
+		public boolean isDrawable() {
+			return !isEmpty();
+		}
+
+		@Override
+		public void toArray(float[] array) {
+			array[0] = this.ctrlX1;
+			array[1] = this.ctrlY1;
+			array[2] = this.ctrlX2;
+			array[3] = this.ctrlY2;
+			array[4] = this.toX;
+			array[5] = this.toY;
+		}
+		
+		@Override
+		public float[] toArray() {
+			return new float[] {this.ctrlX1, this.ctrlY1, this.ctrlX2, this.ctrlY2, this.toX, this.toY};
+		}
+
+		@Override
+		public String toString() {
+			return "CURVE("+ //$NON-NLS-1$
+					this.ctrlX1+"x"+ //$NON-NLS-1$
+					this.ctrlY1+"|"+ //$NON-NLS-1$
+					this.ctrlX2+"x"+ //$NON-NLS-1$
+					this.ctrlY2+"|"+ //$NON-NLS-1$
+					this.toX+"x"+ //$NON-NLS-1$
+					this.toY+")"; //$NON-NLS-1$
+		}
+
+	}
+
+	/** An element of the path that represents a <code>CLOSE</code>.
+	 *
+	 * @author $Author: galland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	public static class ClosePathElement2f extends PathElement2f {
+		
+		private static final long serialVersionUID = 4643537091880303796L;
+
+		/**
+		 * @param fromx
+		 * @param fromy
+		 * @param tox
+		 * @param toy
+		 */
+		public ClosePathElement2f(float fromx, float fromy, float tox, float toy) {
+			super(PathElementType.CLOSE,
+					fromx, fromy,
+					Float.NaN, Float.NaN,
+					Float.NaN, Float.NaN,
+					tox, toy);
+		}
+		
+		@Override
+		public boolean isEmpty() {
+			return (this.fromX==this.toX) && (this.fromY==this.toY);
+		}
+		
+		@Override
+		public boolean isDrawable() {
+			return false;
+		}
+
+		@Override
+		public void toArray(float[] array) {
+			//
+		}
+		
+		@Override
+		public float[] toArray() {
+			return new float[0];
+		}
+		
+		@Override
+		public String toString() {
+			return "CLOSE"; //$NON-NLS-1$
+		}
+
+	}
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathElementType.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathElementType.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathElementType.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,54 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2005-09 Stephane GALLAND.
+ * Copyright (C) 2012 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+
+/** Type of a path element.
+ *
+ * @author $Author: galland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public enum PathElementType {
+
+	/** Move to the next point.
+	 */
+	MOVE_TO,
+
+	/** Line to the next point.
+	 */
+	LINE_TO,
+
+	/** Quadratic curve to the next point.
+	 */
+	QUAD_TO,
+
+	/** Cubic curve to the next point.
+	 */
+	CURVE_TO,
+
+	/** Close the path.
+	 */
+	CLOSE;
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathIterator2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathIterator2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathIterator2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,44 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2005-09 Stephane GALLAND.
+ * Copyright (C) 2012 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import java.util.Iterator;
+
+import org.arakhne.afc.math.generic.PathWindingRule;
+
+
+/** This interface describes an interator on path elements.
+ *
+ * @author $Author: galland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public interface PathIterator2f extends Iterator<PathElement2f> {
+
+	/** Replies the winding rule for the path.
+	 * 
+	 * @return the winding rule for the path.
+	 */
+	public PathWindingRule getWindingRule();
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathWindingRule.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathWindingRule.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/PathWindingRule.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,56 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2005-09 Stephane GALLAND.
+ * Copyright (C) 2012 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+
+/** The winding rule to determine the interior of a path.
+ *
+ * @author $Author: galland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public enum PathWindingRule {
+
+	/** he winding rule constant for specifying an even-odd rule
+     * for determining the interior of a path.
+     * The even-odd rule specifies that a point lies inside the
+     * path if a ray drawn in any direction from that point to
+     * infinity is crossed by path segments an odd number of times.
+     * <p>
+     * <center><img src="./doc-files/fillrule-evenodd.png" /></center>
+	 */
+	EVEN_ODD,
+
+	/** The winding rule constant for specifying a non-zero rule
+     * for determining the interior of a path.
+     * The non-zero rule specifies that a point lies inside the
+     * path if a ray drawn in any direction from that point to
+     * infinity is crossed by path segments a different number
+     * of times in the counter-clockwise direction than the
+     * clockwise direction.
+     * <p>
+     * <center><img src="./doc-files/fillrule-nonzero.png" /></center>
+	 */
+	NON_ZERO;
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Point2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Point2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Point2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,208 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2012 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Tuple2D;
+import org.arakhne.afc.math.generic.Vector2D;
+
+/** 2D Point with 2 floating-point numbers.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class Point2f extends Tuple2f<Point2D> implements Point2D {
+
+	private static final long serialVersionUID = 8963319137253544821L;
+
+	/**
+	 */
+	public Point2f() {
+		//
+	}
+
+	/**
+	 * @param tuple is the tuple to copy.
+	 */
+	public Point2f(Tuple2D<?> tuple) {
+		super(tuple);
+	}
+
+	/**
+	 * @param tuple is the tuple to copy.
+	 */
+	public Point2f(int[] tuple) {
+		super(tuple);
+	}
+
+	/**
+	 * @param tuple is the tuple to copy.
+	 */
+	public Point2f(float[] tuple) {
+		super(tuple);
+	}
+
+	/**
+	 * @param x
+	 * @param y
+	 */
+	public Point2f(int x, int y) {
+		super(x,y);
+	}
+
+	/**
+	 * @param x
+	 * @param y
+	 */
+	public Point2f(float x, float y) {
+		super(x,y);
+	}
+
+	/**
+	 * @param x
+	 * @param y
+	 */
+	public Point2f(double x, double y) {
+		super((float)x,(float)y);
+	}
+
+	/**
+	 * @param x
+	 * @param y
+	 */
+	public Point2f(long x, long y) {
+		super(x,y);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Point2f clone() {
+		return (Point2f)super.clone();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public float distanceSquared(Point2D p1) {
+	      float dx, dy;
+	      dx = this.x-p1.getX();  
+	      dy = this.y-p1.getY();
+	      return (dx*dx+dy*dy);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public float distance(Point2D p1) {
+	      float  dx, dy;
+	      dx = this.x-p1.getX();  
+	      dy = this.y-p1.getY();
+	      return (float)Math.sqrt(dx*dx+dy*dy);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public float distanceL1(Point2D p1) {
+	      return (Math.abs(this.x-p1.getX()) + Math.abs(this.y-p1.getY()));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public float distanceLinf(Point2D p1) {
+	      return Math.max( Math.abs(this.x-p1.getX()), Math.abs(this.y-p1.getY()));
+	}
+
+	@Override
+	public void add(Point2D t1, Vector2D t2) {
+		this.x = t1.getX() + t2.getX();
+		this.y = t1.getY() + t2.getY();
+	}
+
+	@Override
+	public void add(Vector2D t1, Point2D t2) {
+		this.x = t1.getX() + t2.getX();
+		this.y = t1.getY() + t2.getY();
+	}
+
+	@Override
+	public void add(Vector2D t1) {
+		this.x += t1.getX();
+		this.y += t1.getY();
+	}
+
+	@Override
+	public void scaleAdd(int s, Vector2D t1, Point2D t2) {
+		this.x = s * t1.getX() + t2.getX();
+		this.y = s * t1.getY() + t2.getY();
+	}
+
+	@Override
+	public void scaleAdd(float s, Vector2D t1, Point2D t2) {
+		this.x = s * t1.getX() + t2.getX();
+		this.y = s * t1.getY() + t2.getY();
+	}
+
+	@Override
+	public void scaleAdd(int s, Point2D t1, Vector2D t2) {
+		this.x = s * t1.getX() + t2.getX();
+		this.y = s * t1.getY() + t2.getY();
+	}
+
+	@Override
+	public void scaleAdd(float s, Point2D t1, Vector2D t2) {
+		this.x = s * t1.getX() + t2.getX();
+		this.y = s * t1.getY() + t2.getY();
+	}
+
+	@Override
+	public void scaleAdd(int s, Vector2D t1) {
+		this.x = s * this.x + t1.getX();
+		this.y = s * this.y + t1.getY();
+	}
+
+	@Override
+	public void scaleAdd(float s, Vector2D t1) {
+		this.x = s * this.x + t1.getX();
+		this.y = s * this.y + t1.getY();
+	}
+
+	@Override
+	public void sub(Point2D t1, Vector2D t2) {
+		this.x = t1.getX() - t2.getX();
+		this.y = t1.getY() - t2.getY();
+	}
+
+	@Override
+	public void sub(Vector2D t1) {
+		this.x -= t1.getX();
+		this.y -= t1.getY();
+	}
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Rectangle2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Rectangle2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Rectangle2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,900 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import java.util.NoSuchElementException;
+
+import org.arakhne.afc.math.MathUtil;
+import org.arakhne.afc.math.generic.PathWindingRule;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.generic.Vector2D;
+import org.arakhne.afc.math.matrix.Transform2D;
+
+
+
+/** 2D rectangle with floating-point points.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class Rectangle2f extends AbstractRectangularShape2f<Rectangle2f> {
+
+	private static final long serialVersionUID = 8716296371653330467L;
+
+	/** Replies if two rectangles are intersecting.
+	 * 
+	 * @param x1 is the first corner of the first rectangle.
+	 * @param y1 is the first corner of the first rectangle.
+	 * @param x2 is the second corner of the first rectangle.
+	 * @param y2 is the second corner of the first rectangle.
+	 * @param x3 is the first corner of the second rectangle.
+	 * @param y3 is the first corner of the second rectangle.
+	 * @param x4 is the second corner of the second rectangle.
+	 * @param y4 is the second corner of the second rectangle.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsRectangleRectangle(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		assert(x1<=x2);
+		assert(y1<=y2);
+		assert(x3<=x4);
+		assert(y3<=y4);
+		return x2 > x3
+				&&
+				x1 < x4
+				&&
+				y2 > y3
+				&&
+				y1 < y4;
+	}
+
+	/** Replies if two rectangles are intersecting.
+	 * 
+	 * @param x1 is the first corner of the rectangle.
+	 * @param y1 is the first corner of the rectangle.
+	 * @param x2 is the second corner of the rectangle.
+	 * @param y2 is the second corner of the rectangle.
+	 * @param x3 is the first point of the line.
+	 * @param y3 is the first point of the line.
+	 * @param x4 is the second point of the line.
+	 * @param y4 is the second point of the line.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsRectangleLine(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		int a, b;
+		a = MathUtil.ccw(x3, y3, x4, y4, x1, y1, false);
+		b = MathUtil.ccw(x3, y3, x4, y4, x2, y1, false);
+		if (a!=b && b!=0) return true;
+		b = MathUtil.ccw(x3, y3, x4, y4, x2, y2, false);
+		if (a!=b && b!=0) return true;
+		b = MathUtil.ccw(x3, y3, x4, y4, x1, y2, false);
+		return (a!=b && b!=0);
+	}
+
+	private static final int CS_INSIDE = 0; // 0000
+	private static final int CS_LEFT = 1; // 0001
+	private static final int CS_RIGHT = 2; // 0010
+	private static final int CS_BOTTOM = 4; // 0100
+	private static final int CS_TOP = 8; // 1000
+
+	private static int getCohenSutherlandRegion(float x1, float y1, float x2, float y2, float px, float py) {
+		int region = CS_INSIDE;
+		if (px<x1) {
+			region |= CS_LEFT;
+		}
+		else if (px>x2) {
+			region |= CS_RIGHT;
+		}
+		if (py<y1) {
+			region |= CS_BOTTOM;
+		}
+		else if (py>y2) {
+			region |= CS_TOP;
+		}
+		return region;
+	}
+
+	/** Replies if two rectangles are intersecting.
+	 * 
+	 * @param x1 is the first corner of the rectangle.
+	 * @param y1 is the first corner of the rectangle.
+	 * @param x2 is the second corner of the rectangle.
+	 * @param y2 is the second corner of the rectangle.
+	 * @param x3 is the first point of the segment.
+	 * @param y3 is the first point of the segment.
+	 * @param x4 is the second point of the segment.
+	 * @param y4 is the second point of the segment.
+	 * @return <code>true</code> if the two shapes are intersecting; otherwise
+	 * <code>false</code>
+	 */
+	public static boolean intersectsRectangleSegment(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
+		float px1 = x3;
+		float py1 = y3;
+		float px2 = x4;
+		float py2 = y4;
+
+		// Cohen–Sutherland algorithm
+		int r1 = getCohenSutherlandRegion(x1, y1, x2, y2, px1, py1);
+		int r2 = getCohenSutherlandRegion(x1, y1, x2, y2, px2, py2);
+		boolean accept = false;
+
+		while (true) {
+			if ((r1 | r2)==0) {
+				// Bitwise OR is 0. Trivially accept and get out of loop
+				accept =  true;
+				break;//to speed up the algorithm
+			}
+			if ((r1 & r2)!=0) {
+				// Bitwise AND is not 0. Trivially reject and get out of loop
+				break;
+			}
+
+			// failed both tests, so calculate the line segment to clip
+			// from an outside point to an intersection with clip edge
+			float x, y;
+
+			// At least one endpoint is outside the clip rectangle; pick it.
+			int outcodeOut = r1!=0 ? r1 : r2;
+
+			// Now find the intersection point;
+			// use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
+			if ((outcodeOut & CS_TOP)!=0) { // point is above the clip rectangle
+				x = px1 + (px2 - px1) * (y2 - py1) / (py2 - py1);
+				y = y2;
+			}
+			else if ((outcodeOut & CS_BOTTOM)!=0) { // point is below the clip rectangle
+				x = px1 + (px2 - px1) * (y1- py1) / (py2 - py1);
+				y = y1;
+			}
+			else if ((outcodeOut & CS_RIGHT)!=0) {  // point is to the right of clip rectangle
+				y = py1 + (py2 - py1) * (x2 - px1) / (px2 - px1);
+				x = x2;
+			}
+			else {
+				//else if ((outcodeOut & CS_LEFT)!=0) {   // point is to the left of clip rectangle
+				y = py1 + (py2 - py1) * (x1 - px1) / (px2 - px1);
+				x = x1;
+			}
+
+			//NOTE:*****************************************************************************************
+
+			/* if you follow this algorithm exactly(at least for c#), then you will fall into an infinite loop 
+            in case a line crosses more than two segments. to avoid that problem, leave out the last else
+            if(outcodeOut & LEFT) and just make it else*/
+
+			//**********************************************************************************************
+
+			// Now we move outside point to intersection point to clip
+			// and get ready for next pass.
+			if (outcodeOut == r1) {
+				px1 = x;
+				py1 = y;
+				r1 = getCohenSutherlandRegion(x1, y1, x2, y2, px1, py1);
+			}
+			else {
+				px2 = x;
+				py2 = y;
+				r2 = getCohenSutherlandRegion(x1, y1, x2, y2, px2, py2);
+			}
+		}
+
+		return accept;
+	}
+
+	/** Compute the union of r1 and r2.
+	 * 
+	 * @param dest is the union.
+	 * @param r1
+	 * @param r2
+	 */
+	public static void union(Rectangle2f dest, Rectangle2f r1, Rectangle2f r2) {
+		dest.setFromCorners(
+				Math.min(r1.getMinX(), r2.getMinX()),
+				Math.min(r1.getMinY(), r2.getMinY()),
+				Math.max(r1.getMaxX(), r2.getMaxX()),
+				Math.max(r1.getMaxY(), r2.getMaxY()));
+	}
+
+	/** Replies if a rectangle is inside in the rectangle.
+	 * 
+	 * @param rx1 is the lowest corner of the enclosing-candidate rectangle.
+	 * @param ry1 is the lowest corner of the enclosing-candidate rectangle.
+	 * @param rwidth1 is the width of the enclosing-candidate rectangle.
+	 * @param rheight1 is the height of the enclosing-candidate rectangle.
+	 * @param rx2 is the lowest corner of the inner-candidate rectangle.
+	 * @param ry2 is the lowest corner of the inner-candidate rectangle.
+	 * @param rwidth2 is the width of the inner-candidate rectangle.
+	 * @param rheight2 is the height of the inner-candidate rectangle.
+	 * @return <code>true</code> if the given rectangle is inside the ellipse;
+	 * otherwise <code>false</code>.
+	 */
+	public static boolean containsRectangleRectangle(float rx1, float ry1, float rwidth1, float rheight1, float rx2, float ry2, float rwidth2, float rheight2) {
+		if (rwidth1<=0f || rwidth2<=0f || rheight1<=0 || rheight2<=0f) {
+            return false;
+        }
+        return (rx2 >= rx1 &&
+                ry2 >= ry1 &&
+                (rx2 + rwidth2) <= rx1 + rwidth1 &&
+                (ry2 + rheight2) <= ry1 + rheight1);
+	}
+
+	/** Compute the intersection of r1 and r2.
+	 * 
+	 * @param dest is the intersection.
+	 * @param r1
+	 * @param r2
+	 */
+	public static void intersection(Rectangle2f dest, Rectangle2f r1, Rectangle2f r2) {
+		float x1 = Math.max(r1.getMinX(), r2.getMinX());
+		float y1 = Math.max(r1.getMinY(), r2.getMinY());
+		float x2 = Math.min(r1.getMaxX(), r2.getMaxX());
+		float y2 = Math.min(r1.getMaxY(), r2.getMaxY());
+		if (x1<=x2 && y1<=y2) {
+			dest.setFromCorners(x1, y1, x2, y2);
+		}
+		else {
+			dest.set(0, 0, 0, 0);
+		}
+	}
+
+	/**
+	 */
+	public Rectangle2f() {
+		//
+	}
+
+	/**
+	 * @param min is the min corner of the rectangle.
+	 * @param max is the max corner of the rectangle.
+	 */
+	public Rectangle2f(Point2f min, Point2f max) {
+		super(min, max);
+	}
+
+	/**
+	 * @param x
+	 * @param y
+	 * @param width
+	 * @param height
+	 */
+	public Rectangle2f(float x, float y, float width, float height) {
+		super(x, y, width, height);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Rectangle2f toBoundingBox() {
+		return this;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceSquared(Point2D p) {
+		float dx;
+		if (p.getX()<getMinX()) {
+			dx = getMinX() - p.getX();
+		}
+		else if (p.getX()>getMaxX()) {
+			dx = p.getX() - getMaxX();
+		}
+		else {
+			dx = 0f;
+		}
+		float dy;
+		if (p.getY()<getMinY()) {
+			dy = getMinY() - p.getY();
+		}
+		else if (p.getY()>getMaxY()) {
+			dy = p.getY() - getMaxY();
+		}
+		else {
+			dy = 0f;
+		}
+		return dx*dx+dy*dy;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceL1(Point2D p) {
+		float dx;
+		if (p.getX()<getMinX()) {
+			dx = getMinX() - p.getX();
+		}
+		else if (p.getX()>getMaxX()) {
+			dx = p.getX() - getMaxX();
+		}
+		else {
+			dx = 0f;
+		}
+		float dy;
+		if (p.getY()<getMinY()) {
+			dy = getMinY() - p.getY();
+		}
+		else if (p.getY()>getMaxY()) {
+			dy = p.getY() - getMaxY();
+		}
+		else {
+			dy = 0f;
+		}
+		return dx + dy;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public float distanceLinf(Point2D p) {
+		float dx;
+		if (p.getX()<getMinX()) {
+			dx = getMinX() - p.getX();
+		}
+		else if (p.getX()>getMaxX()) {
+			dx = p.getX() - getMaxX();
+		}
+		else {
+			dx = 0f;
+		}
+		float dy;
+		if (p.getY()<getMinY()) {
+			dy = getMinY() - p.getY();
+		}
+		else if (p.getY()>getMaxY()) {
+			dy = p.getY() - getMaxY();
+		}
+		else {
+			dy = 0f;
+		}
+		return Math.max(dx, dy);
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean contains(float x, float y) {
+		return (x>=getMinX() && x<=getMaxX())
+				&&
+				(y>=getMinY() && y<=getMaxY());
+	}
+	
+	@Override
+	public boolean contains(Rectangle2f r) {
+		return containsRectangleRectangle(
+				getMinX(), getMinY(), getWidth(), getHeight(),
+				r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight());
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public Point2D getClosestPointTo(Point2D p) {
+		float x;
+		int same = 0;
+		if (p.getX()<getMinX()) {
+			x = getMinX();
+		}
+		else if (p.getX()>getMaxX()) {
+			x = getMaxX();
+		}
+		else {
+			x = p.getX();
+			++same;
+		}
+		float y;
+		if (p.getY()<getMinY()) {
+			y = getMinY();
+		}
+		else if (p.getY()>getMaxY()) {
+			y = getMaxY();
+		}
+		else {
+			y = p.getY();
+			++same;
+		}
+		if (same==2) return p;
+		return new Point2f(x,y);
+	}
+
+	/** Add the given coordinate in the rectangle.
+	 * <p>
+	 * The corners of the rectangles are moved to
+	 * enclosed the given coordinate.
+	 * 
+	 * @param p
+	 */
+	public void add(Point2D p) {
+		add(p.getX(), p.getY());
+	}
+
+	/** Add the given coordinate in the rectangle.
+	 * <p>
+	 * The corners of the rectangles are moved to
+	 * enclosed the given coordinate.
+	 * 
+	 * @param x
+	 * @param y
+	 */
+	public void add(float x, float y) {
+		if (x<getMinX()) {
+			setMinX(x);
+		}
+		else if (x>getMaxX()) {
+			setMaxX(x);
+		}
+		if (y<getMinY()) {
+			setMinY(y);
+		}
+		else if (y>getMaxY()) {
+			setMaxY(y);
+		}
+	}
+
+	/** Compute and replies the union of this rectangle and the given rectangle.
+	 * This function does not change this rectangle.
+	 * <p>
+	 * It is equivalent to (where <code>ur</code> is the union):
+	 * <pre><code>
+	 * Rectangle2f ur = new Rectangle2f();
+	 * Rectangle2f.union(ur, this, r);
+	 * </code></pre>
+	 * 
+	 * @param r
+	 * @return the union of this rectangle and the given rectangle.
+	 * @see #union(Rectangle2f, Rectangle2f, Rectangle2f)
+	 * @see #setUnion(Rectangle2f)
+	 */
+	public Rectangle2f createUnion(Rectangle2f r) {
+		Rectangle2f rr = new Rectangle2f();
+		union(rr, this, r);
+		return rr;
+	}
+
+	/** Compute and replies the intersection of this rectangle and the given rectangle.
+	 * This function does not change this rectangle.
+	 * <p>
+	 * It is equivalent to (where <code>ir</code> is the intersection):
+	 * <pre><code>
+	 * Rectangle2f ir = new Rectangle2f();
+	 * Rectangle2f.intersection(ir, this, r);
+	 * </code></pre>
+	 * 
+	 * @param r
+	 * @return the union of this rectangle and the given rectangle.
+	 * @see #intersection(Rectangle2f, Rectangle2f, Rectangle2f)
+	 * @see #setIntersection(Rectangle2f)
+	 */
+	public Rectangle2f createIntersection(Rectangle2f r) {
+		Rectangle2f rr = new Rectangle2f();
+		intersection(rr, this, r);
+		return rr;
+	}
+
+	/** Compute the union of this rectangle and the given rectangle and
+	 * change this rectangle with the result of the union.
+	 * <p>
+	 * It is equivalent to:
+	 * <pre><code>
+	 * Rectangle2f.union(this, this, r);
+	 * </code></pre>
+	 * 
+	 * @param r
+	 * @see #union(Rectangle2f, Rectangle2f, Rectangle2f)
+	 * @see #createUnion(Rectangle2f)
+	 */
+	public void setUnion(Rectangle2f r) {
+		union(this, this, r);
+	}
+
+	/** Compute the intersection of this rectangle and the given rectangle.
+	 * This function does not change this rectangle.
+	 * <p>
+	 * It is equivalent to:
+	 * <pre><code>
+	 * Rectangle2f.intersection(this, this, r);
+	 * </code></pre>
+	 * 
+	 * @param r
+	 * @see #intersection(Rectangle2f, Rectangle2f, Rectangle2f)
+	 * @see #createIntersection(Rectangle2f)
+	 */
+	public void setIntersection(Rectangle2f r) {
+		intersection(this, this, r);
+	}
+
+	@Override
+	public PathIterator2f getPathIterator(Transform2D transform) {
+		if (transform==null) {
+			return new CopyPathIterator(
+					getMinX(), getMinY(),
+					getMaxX(), getMaxY());
+		}
+		return new TransformPathIterator(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				transform);
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (obj instanceof Rectangle2f) {
+			Rectangle2f rr2d = (Rectangle2f) obj;
+			return ((getMinX() == rr2d.getMinX()) &&
+					(getMinY() == rr2d.getMinY()) &&
+					(getWidth() == rr2d.getWidth()) &&
+					(getHeight() == rr2d.getHeight()));
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		long bits = 1L;
+		bits = 31L * bits + floatToIntBits(getMinX());
+		bits = 31L * bits + floatToIntBits(getMinY());
+		bits = 31L * bits + floatToIntBits(getMaxX());
+		bits = 31L * bits + floatToIntBits(getMaxY());
+		return (int) (bits ^ (bits >> 32));
+	}
+
+	@Override
+	public boolean intersects(Rectangle2f s) {
+		return intersectsRectangleRectangle(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				s.getMinX(), s.getMinY(),
+				s.getMaxX(), s.getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Ellipse2f s) {
+		return Ellipse2f.intersectsEllipseRectangle(
+				s.getMinX(), s.getMinY(),
+				s.getMaxX(), s.getMaxY(),
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Circle2f s) {
+		return Circle2f.intersectsCircleRectangle(
+				s.getX(), s.getY(),
+				s.getRadius(),
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Segment2f s) {
+		return intersectsRectangleSegment(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				s.getX1(), s.getY1(),
+				s.getX2(), s.getY2());
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append("["); //$NON-NLS-1$
+		b.append(getMinX());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMinY());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMaxX());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMaxY());
+		b.append("]"); //$NON-NLS-1$
+		return b.toString();
+	}
+	
+	/** Move this rectangle to avoid collision 
+	 * with the reference rectangle.
+	 * 
+	 * @param reference is the rectangle to avoid collision with.
+	 * @return the displacement vector.
+	 */
+	public Vector2D avoidCollisionWith(Rectangle2f reference) {
+		float dx1 = reference.getMaxX() - getMinX();
+		float dx2 = getMaxX() - reference.getMinX();
+		float dy1 = reference.getMaxY() - getMinY();
+		float dy2 = getMaxY() - reference.getMinY();
+
+		float absdx1 = Math.abs(dx1);
+		float absdx2 = Math.abs(dx2);
+		float absdy1 = Math.abs(dy1);
+		float absdy2 = Math.abs(dy2);
+
+		float dx = 0;
+		float dy = 0;
+
+		if (dx1>=0 && absdx1<=absdx2 && absdx1<=absdy1 && absdx1<=absdy2) {
+			// Move according to dx1
+			dx = dx1; 
+		}
+		else if (dx2>=0 && absdx2<=absdx1 && absdx2<=absdy1 && absdx2<=absdy2) {
+			// Move according to dx2
+			dx = - dx2;
+		}
+		else if (dy1>=0 && absdy1<=absdx1 && absdy1<=absdx2 && absdy1<=absdy2) {
+			// Move according to dy1
+			dy = dy1; 
+		}
+		else {
+			// Move according to dy2
+			dy = - dy2;
+		}
+
+		set(
+				getMinX()+dx,
+				getMinY()+dy,
+				getWidth(),
+				getHeight());
+		
+		return new Vector2f(dx, dy);
+	}
+
+	/** Move this rectangle to avoid collision 
+	 * with the reference rectangle.
+	 * 
+	 * @param reference is the rectangle to avoid collision with.
+	 * @param displacementDirection is the direction of the allowed displacement.
+	 * @return the displacement vector.
+	 */
+	public Vector2D avoidCollisionWith(Rectangle2f reference, Vector2D displacementDirection) {
+		if (displacementDirection==null || displacementDirection.lengthSquared()==0f)
+			return avoidCollisionWith(reference);
+		
+		float dx1 = reference.getMaxX() - getMinX();
+		float dx2 = reference.getMinX() - getMaxX();
+		float dy1 = reference.getMaxY() - getMinY();
+		float dy2 = reference.getMinY() - getMaxY();
+
+		float absdx1 = Math.abs(dx1);
+		float absdx2 = Math.abs(dx2);
+		float absdy1 = Math.abs(dy1);
+		float absdy2 = Math.abs(dy2);
+		
+		float dx, dy;
+		
+		if (displacementDirection.getX()<0) {
+			dx = -Math.min(absdx1, absdx2);
+		}
+		else {
+			dx = Math.min(absdx1, absdx2);
+		}
+
+		if (displacementDirection.getY()<0) {
+			dy = -Math.min(absdy1, absdy2);
+		}
+		else {
+			dy = Math.min(absdy1, absdy2);
+		}
+
+		set(
+				getMinX()+dx,
+				getMinY()+dy,
+				getWidth(),
+				getHeight());
+
+		displacementDirection.set(dx, dy);
+		return displacementDirection;
+	}
+
+	/** Iterator on the path elements of the rectangle.
+	 * 
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private static class CopyPathIterator implements PathIterator2f {
+		
+		private final float x1;
+		private final float y1;
+		private final float x2;
+		private final float y2;
+		private int index = 0;
+		
+		/**
+		 * @param x1
+		 * @param y1
+		 * @param x2
+		 * @param y2
+		 */
+		public CopyPathIterator(float x1, float y1, float x2, float y2) {
+			this.x1 = Math.min(x1, x2);
+			this.y1 = Math.min(y1, y2);
+			this.x2 = Math.max(x1, x2);
+			this.y2 = Math.max(y1, y2);
+			if (Math.abs(this.x1-this.x2)<=0f || Math.abs(this.y1-this.y2)<=0f) {
+				this.index = 6;
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.index<=5;
+		}
+
+		@Override
+		public PathElement2f next() {
+			int idx = this.index;
+			++this.index;
+			switch(idx) {
+			case 0:
+				return new PathElement2f.MovePathElement2f(
+						this.x1, this.y1);
+			case 1:
+				return new PathElement2f.LinePathElement2f(
+						this.x1, this.y1,
+						this.x2, this.y1);
+			case 2:
+				return new PathElement2f.LinePathElement2f(
+						this.x2, this.y1,
+						this.x2, this.y2);
+			case 3:
+				return new PathElement2f.LinePathElement2f(
+						this.x2, this.y2,
+						this.x1, this.y2);
+			case 4:
+				return new PathElement2f.LinePathElement2f(
+						this.x1, this.y2,
+						this.x1, this.y1);
+			case 5:
+				return new PathElement2f.ClosePathElement2f(
+						this.x1, this.y1,
+						this.x1, this.y1);
+			default:
+				throw new NoSuchElementException();
+			}
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return PathWindingRule.NON_ZERO;
+		}
+		
+	}
+
+	/** Iterator on the path elements of the rectangle.
+	 * 
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private static class TransformPathIterator implements PathIterator2f {
+		
+		private final Transform2D transform;
+		private final float x1;
+		private final float y1;
+		private final float x2;
+		private final float y2;
+		private int index = 0;
+		
+		private final Point2D p1 = new Point2f();
+		private final Point2D p2 = new Point2f();
+		
+		/**
+		 * @param x1
+		 * @param y1
+		 * @param x2
+		 * @param y2
+		 * @param transform
+		 */
+		public TransformPathIterator(float x1, float y1, float x2, float y2, Transform2D transform) {
+			this.transform = transform;
+			this.x1 = Math.min(x1, x2);
+			this.y1 = Math.min(y1, y2);
+			this.x2 = Math.max(x1, x2);
+			this.y2 = Math.max(y1, y2);
+			if (Math.abs(this.x1-this.x2)<=0f || Math.abs(this.y1-this.y2)<=0f) {
+				this.index = 6;
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.index<=5;
+		}
+
+		@Override
+		public PathElement2f next() {
+			int idx = this.index;
+			++this.index;
+			switch(idx) {
+			case 0:
+				this.p2.set(this.x1, this.y1);
+				if (this.transform!=null) {
+					this.transform.transform(this.p2);
+				}
+				return new PathElement2f.MovePathElement2f(
+						this.p2.getX(), this.p2.getY());
+			case 1:
+				this.p1.set(this.p2);
+				this.p2.set(this.x2, this.y1);
+				if (this.transform!=null) {
+					this.transform.transform(this.p2);
+				}
+				return new PathElement2f.LinePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.p2.getX(), this.p2.getY());
+			case 2:
+				this.p1.set(this.p2);
+				this.p2.set(this.x2, this.y2);
+				if (this.transform!=null) {
+					this.transform.transform(this.p2);
+				}
+				return new PathElement2f.LinePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.p2.getX(), this.p2.getY());
+			case 3:
+				this.p1.set(this.p2);
+				this.p2.set(this.x1, this.y2);
+				if (this.transform!=null) {
+					this.transform.transform(this.p2);
+				}
+				return new PathElement2f.LinePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.p2.getX(), this.p2.getY());
+			case 4:
+				this.p1.set(this.p2);
+				this.p2.set(this.x1, this.y1);
+				if (this.transform!=null) {
+					this.transform.transform(this.p2);
+				}
+				return new PathElement2f.LinePathElement2f(
+						this.p1.getX(), this.p1.getY(),
+						this.p2.getX(), this.p2.getY());
+			case 5:
+				return new PathElement2f.ClosePathElement2f(
+						this.p2.getX(), this.p2.getY(),
+						this.p2.getX(), this.p2.getY());
+			default:
+				throw new NoSuchElementException();
+			}
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return PathWindingRule.NON_ZERO;
+		}
+		
+	}
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/RoundRectangle2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/RoundRectangle2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/RoundRectangle2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,699 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+package org.arakhne.afc.math.continous.object2d;
+
+import java.util.NoSuchElementException;
+
+import org.arakhne.afc.math.MathConstants;
+import org.arakhne.afc.math.MathUtil;
+import org.arakhne.afc.math.generic.PathElementType;
+import org.arakhne.afc.math.generic.PathWindingRule;
+import org.arakhne.afc.math.generic.Point2D;
+import org.arakhne.afc.math.matrix.Transform2D;
+
+
+/** 2D round rectangle with floating-point points.
+ * 
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public class RoundRectangle2f extends AbstractRectangularShape2f<RoundRectangle2f> {
+
+	private static final long serialVersionUID = 4681356809053380781L;
+
+	/** Replies if a rectangle is inside in the round rectangle.
+	 * 
+	 * @param rx1 is the lowest corner of the round rectangle.
+	 * @param ry1 is the lowest corner of the round rectangle.
+	 * @param rwidth1 is the width of the round rectangle.
+	 * @param rheight1 is the height of the round rectangle.
+	 * @param awidth is the width of the arc of the round rectangle.
+	 * @param aheight is the height of the arc of the round rectangle.
+	 * @param rx2 is the lowest corner of the inner-candidate rectangle.
+	 * @param ry2 is the lowest corner of the inner-candidate rectangle.
+	 * @param rwidth2 is the width of the inner-candidate rectangle.
+	 * @param rheight2 is the height of the inner-candidate rectangle.
+	 * @return <code>true</code> if the given rectangle is inside the ellipse;
+	 * otherwise <code>false</code>.
+	 */
+	public static boolean containsRoundRectangleRectangle(float rx1, float ry1, float rwidth1, float rheight1, float awidth, float aheight, float rx2, float ry2, float rwidth2, float rheight2) {
+		float rcx1 = (rx1 + rwidth1/2f);
+		float rcy1 = (ry1 + rheight1/2f);
+		float rcx2 = (rx2 + rwidth2/2f);
+		float rcy2 = (ry2 + rheight2/2f);
+		float farX;
+		if (rcx1<=rcx2) farX = rx2 + rwidth2;
+		else farX = rx2;
+		float farY;
+		if (rcy1<=rcy2) farY = ry2 + rheight2;
+		else farY = ry2;
+		return containsRoundRectanglePoint(rx1, ry1, rwidth1, rheight1, awidth, aheight, farX, farY);
+	}
+
+	/** Replies if a point is inside in the round rectangle.
+	 * 
+	 * @param rx is the lowest corner of the round rectangle.
+	 * @param ry is the lowest corner of the round rectangle.
+	 * @param rwidth is the width of the round rectangle.
+	 * @param rheight is the height of the round rectangle.
+	 * @param awidth is the width of the arc of the round rectangle.
+	 * @param aheight is the height of the arc of the round rectangle.
+	 * @param px is the point.
+	 * @param py is the point.
+	 * @return <code>true</code> if the given rectangle is inside the ellipse;
+	 * otherwise <code>false</code>.
+	 */
+	public static boolean containsRoundRectanglePoint(float rx, float ry, float rwidth, float rheight, float awidth, float aheight, float px, float py) {
+		if (rwidth<=0f && rheight<=0f) {
+			return rx==px && ry==py;
+		}
+		float rx0 = rx;
+		float ry0 = ry;
+		float rrx1 = rx0 + rwidth;
+		float rry1 = ry0 + rheight;
+		// Check for trivial rejection - point is outside bounding rectangle
+		if (px < rx0 || py < ry0 || px >= rrx1 || py >= rry1) {
+			return false;
+		}
+		float aw = Math.min(rwidth, Math.abs(awidth)) / 2f;
+		float ah = Math.min(rheight, Math.abs(aheight)) / 2f;
+		// Check which corner point is in and do circular containment
+		// test - otherwise simple acceptance
+		if (px >= (rx0 += aw) && px < (rx0 = rrx1 - aw)) {
+			return true;
+		}
+		if (py >= (ry0 += ah) && py < (ry0 = rry1 - ah)) {
+			return true;
+		}
+		float xx = (px - rx0) / aw;
+		float yy = (py - ry0) / ah;
+		return (xx * xx + yy * yy <= 1f);
+	}
+
+	private static final float ANGLE = MathConstants.PI / 4f;
+	private static final float A = 1f - (float)Math.cos(ANGLE);
+	private static final float B = (float)Math.tan(ANGLE);
+	private static final float C = (float)Math.sqrt(1f + B * B) - 1f + A;
+	private static final float CV = 4f / 3f * A * B / C;
+	private static final float ACV = (1f - CV) / 2f;
+	
+	/** For each array:
+	 * 4 values for each point {v0, v1, v2, v3}:
+	 * point = (x + v0 * w + v1 * arcWidth,
+	 * y + v2 * h + v3 * arcHeight)
+	 */
+	static float CTRL_PTS[][] = {
+		{  0f,  0f,  0f,  .5f },
+		{  0f,  0f,  1f, -.5f },
+		{  0f,  0f,  1f, -ACV,
+			0f,  ACV,  1f,  0f,
+			0f,  .5f,  1f,  0f },
+			{  1f, -.5f,  1f,  0f },
+			{  1f, -ACV,  1f,  0f,
+				1f,  0f,  1f, -ACV,
+				1f,  0f,  1f, -.5f },
+				{  1f,  0f,  0f,  .5f },
+				{  1f,  0f,  0f,  ACV,
+					1f, -ACV,  0f,  0f,
+					1f, -.5f,  0f,  0f },
+					{  0f,  .5f,  0f,  0f },
+					{  0f,  ACV,  0f,  0f,
+						0f,  0f,  0f,  ACV,
+						0f,  0f,  0f,  .5f },
+						{},
+	};
+	
+	/** Types of path elements for the round rectangle.
+	 */
+	static PathElementType TYPES[] = {
+		PathElementType.MOVE_TO,
+		PathElementType.LINE_TO, PathElementType.CURVE_TO,
+		PathElementType.LINE_TO, PathElementType.CURVE_TO,
+		PathElementType.LINE_TO, PathElementType.CURVE_TO,
+		PathElementType.LINE_TO, PathElementType.CURVE_TO,
+		PathElementType.CLOSE,
+	};
+
+	
+	/** Width of the arcs at the corner of the box. */
+	protected float arcWidth;
+	/** Height of the arcs at the corner of the box. */
+	protected float arcHeight;
+
+	/**
+	 */
+	public RoundRectangle2f() {
+		this.arcHeight = this.arcWidth = 0f;
+	}
+
+	/**
+	 * @param min is the min corner of the rectangle.
+	 * @param max is the max corner of the rectangle.
+	 * @param arcWidth
+	 * @param arcHeight
+	 */
+	public RoundRectangle2f(Point2f min, Point2f max, float arcWidth, float arcHeight) {
+		super(min, max);
+		this.arcWidth = arcWidth;
+		this.arcHeight = arcHeight;
+	}
+
+	/**
+	 * @param x
+	 * @param y
+	 * @param width
+	 * @param height
+	 * @param arcWidth
+	 * @param arcHeight
+	 */
+	public RoundRectangle2f(float x, float y, float width, float height, float arcWidth, float arcHeight) {
+		super(x, y, width, height);
+		this.arcWidth = arcWidth;
+		this.arcHeight = arcHeight;
+	}
+	
+	@Override
+	public void clear() {
+		this.arcHeight = this.arcWidth = 0f;
+		super.clear();
+	}
+
+	/**
+	 * Gets the width of the arc that rounds off the corners.
+	 * @return the width of the arc that rounds off the corners
+	 * of this <code>RoundRectangle2f</code>.
+	 */
+	public float getArcWidth() {
+		return this.arcWidth;
+	}
+
+	/**
+	 * Gets the height of the arc that rounds off the corners.
+	 * @return the height of the arc that rounds off the corners
+	 * of this <code>RoundRectangle2f</code>.
+	 */
+	public float getArcHeight() {
+		return this.arcHeight;
+	}
+
+	/**
+	 * Set the width of the arc that rounds off the corners.
+	 * @param a is the width of the arc that rounds off the corners
+	 * of this <code>RoundRectangle2f</code>.
+	 */
+	public void setArcWidth(float a) {
+		this.arcWidth = a;
+	}
+
+	/**
+	 * Set the height of the arc that rounds off the corners.
+	 * @param a is the height of the arc that rounds off the corners
+	 * of this <code>RoundRectangle2f</code>.
+	 */
+	public void setArcHeight(float a) {
+		this.arcHeight = a;
+	}
+
+	/** {@inheritDoc}
+	 */
+	@Override
+	public boolean contains(float x, float y) {
+		return containsRoundRectanglePoint(
+				getMinX(), getMinY(), getWidth(), getHeight(), getArcWidth(), getArcHeight(),
+				x, y);
+	}
+	
+	@Override
+	public boolean contains(Rectangle2f r) {
+		return containsRoundRectangleRectangle(
+				getMinX(), getMinY(), getWidth(), getHeight(), getArcWidth(), getArcHeight(),
+				r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight());
+	}
+
+	@Override
+	public float distanceSquared(Point2D p) {
+		Point2D n = getClosestPointTo(p);
+		return n.distanceSquared(p);
+	}
+
+	@Override
+	public float distanceL1(Point2D p) {
+		Point2D n = getClosestPointTo(p);
+		return n.distanceL1(p);
+	}
+
+	@Override
+	public float distanceLinf(Point2D p) {
+		Point2D n = getClosestPointTo(p);
+		return n.distanceLinf(p);
+	}
+
+	@Override
+	public Point2D getClosestPointTo(Point2D p) {
+		float px = p.getX();
+		float py = p.getY();
+		float rx1 = getMinX();
+		float ry1 = getMinY();
+		float rx2 = getMaxX();
+		float ry2 = getMaxY();
+
+		float aw = getArcWidth();
+		float ah = getArcHeight();
+
+		int same = 0;
+		float x, y;
+
+		if (px<rx1+aw) {
+			if (py<ry1+ah) {
+				return MathUtil.getClosestPointToSolidEllipse(
+						px, py,
+						rx1, ry1,
+						aw, ah);
+			}
+			if (py>ry2-ah) {
+				return MathUtil.getClosestPointToSolidEllipse(
+						px, py,
+						rx1, ry2-ah,
+						aw, ah);
+			}
+		}
+		else if (px>rx2-aw) {
+			if (py<ry1+ah) {
+				return MathUtil.getClosestPointToSolidEllipse(
+						px, py,
+						rx2-aw, ry1,
+						aw, ah);
+			}
+			if (py>ry2-ah) {
+				return MathUtil.getClosestPointToSolidEllipse(
+						px, py,
+						rx2-aw, ry2-ah,
+						aw, ah);
+			}
+		}
+
+
+		if (px<rx1) {
+			x = rx1;
+		}
+		else if (px>rx2) {
+			x = rx2;
+		}
+		else {
+			x = px;
+			++same;
+		}
+
+		if (py<ry1) {
+			y = ry1;
+		}
+		else if (py>ry2) {
+			y = ry2;
+		}
+		else {
+			y = py;
+			++same;
+		}
+
+		if (same==2) return p;
+		return new Point2f(x,y);
+	}
+
+	@Override
+	public PathIterator2f getPathIterator(Transform2D transform) {
+		if (transform==null) {
+			return new CopyPathIterator(
+					getMinX(), getMinY(),
+					getWidth(), getHeight(),
+					getArcWidth(), getArcHeight());
+		}
+		return new TransformPathIterator(
+				getMinX(), getMinY(),
+				getWidth(), getHeight(),
+				getArcWidth(), getArcHeight(),
+				transform);
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+		if (obj instanceof RoundRectangle2f) {
+			RoundRectangle2f rr2d = (RoundRectangle2f) obj;
+			return ((getMinX() == rr2d.getMinX()) &&
+					(getMinY() == rr2d.getMinY()) &&
+					(getWidth() == rr2d.getWidth()) &&
+					(getHeight() == rr2d.getHeight()) &&
+					(getArcWidth() == rr2d.getArcWidth()) &&
+					(getArcHeight() == rr2d.getArcHeight()));
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		long bits = 1L;
+		bits = 31L * bits + floatToIntBits(getMinX());
+		bits = 31L * bits + floatToIntBits(getMinY());
+		bits = 31L * bits + floatToIntBits(getMaxX());
+		bits = 31L * bits + floatToIntBits(getMaxY());
+		bits = 31L * bits + floatToIntBits(getArcWidth());
+		bits = 31L * bits + floatToIntBits(getArcHeight());
+		return (int) (bits ^ (bits >> 32));
+	}
+
+	@Override
+	public Rectangle2f toBoundingBox() {
+		return new Rectangle2f(getMinX(), getMinY(), getWidth(), getHeight());
+	}
+
+	@Override
+	public boolean intersects(Rectangle2f s) {
+		return Rectangle2f.intersectsRectangleRectangle(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				s.getMinX(), s.getMinY(),
+				s.getMaxX(), s.getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Ellipse2f s) {
+		return Ellipse2f.intersectsEllipseRectangle(
+				s.getMinX(), s.getMinY(),
+				s.getMaxX(), s.getMaxY(),
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Circle2f s) {
+		return Circle2f.intersectsCircleRectangle(
+				s.getX(), s.getY(),
+				s.getRadius(),
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY());
+	}
+
+	@Override
+	public boolean intersects(Segment2f s) {
+		return Rectangle2f.intersectsRectangleSegment(
+				getMinX(), getMinY(),
+				getMaxX(), getMaxY(),
+				s.getX1(), s.getY1(),
+				s.getX2(), s.getY2());
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		b.append("["); //$NON-NLS-1$
+		b.append(getMinX());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMinY());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMaxX());
+		b.append(";"); //$NON-NLS-1$
+		b.append(getMaxY());
+		b.append("|"); //$NON-NLS-1$
+		b.append(getArcWidth());
+		b.append("x"); //$NON-NLS-1$
+		b.append(getArcHeight());
+		b.append("]"); //$NON-NLS-1$
+		return b.toString();
+	}
+
+	/** Iterator on the path elements of the rectangle.
+	 * 
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private static class CopyPathIterator implements PathIterator2f {
+		
+		private final float x;
+		private final float y;
+		private final float w;
+		private final float h;
+		private final float aw;
+		private final float ah;
+		private int index = 0;
+		
+		private float moveX, moveY, lastX,  lastY;
+		
+		/**
+		 * @param x
+		 * @param y
+		 * @param w
+		 * @param h
+		 * @param aw
+		 * @param ah
+		 */
+		public CopyPathIterator(float x, float y, float w, float h, float aw, float ah) {
+			this.x = x;
+			this.y = y;
+			this.w = Math.max(0f, w);
+			this.h = Math.max(0f, h);
+			this.aw = Math.min(Math.abs(aw), w);
+			this.ah = Math.min(Math.abs(ah), h);
+			if (this.w<=0f || this.h<=0f) {
+				this.index = TYPES.length;
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.index<TYPES.length;
+		}
+		
+		@Override
+		public PathElement2f next() {
+			if (this.index>=TYPES.length) throw new NoSuchElementException();
+			int idx = this.index;
+
+			PathElement2f element = null;
+			PathElementType type = TYPES[idx];
+			float ctrls[] = CTRL_PTS[idx];
+			float ix, iy;
+			float ctrlx1, ctrly1, ctrlx2, ctrly2;
+			
+			switch(type) {
+			case MOVE_TO:
+				this.moveX = this.lastX = this.x + ctrls[0] * this.w + ctrls[1] * this.aw;
+				this.moveY = this.lastY = this.y + ctrls[2] * this.h + ctrls[3] * this.ah;
+		        element = new PathElement2f.MovePathElement2f(
+		        		this.lastX, this.lastY);
+		        break;
+			case LINE_TO:
+				ix = this.lastX;
+				iy = this.lastY;
+				this.lastX = this.x + ctrls[0] * this.w + ctrls[1] * this.aw;
+				this.lastY = this.y + ctrls[2] * this.h + ctrls[3] * this.ah;
+		        element = new PathElement2f.LinePathElement2f(
+		        		ix, iy,
+		        		this.lastX, this.lastY);
+		        break;
+			case CURVE_TO:
+				ix = this.lastX;
+				iy = this.lastY;
+				ctrlx1 = this.x + ctrls[0] * this.w + ctrls[1] * this.aw;
+				ctrly1 = this.y + ctrls[2] * this.h + ctrls[3] * this.ah;
+				ctrlx2 = this.x + ctrls[4] * this.w + ctrls[5] * this.aw;
+				ctrly2 = this.y + ctrls[6] * this.h + ctrls[7] * this.ah;
+				this.lastX = this.x + ctrls[8] * this.w + ctrls[9] * this.aw;
+				this.lastY = this.y + ctrls[10] * this.h + ctrls[11] * this.ah;
+		        element = new PathElement2f.CurvePathElement2f(
+		        		ix, iy,
+		        		ctrlx1, ctrly1,
+		        		ctrlx2, ctrly2,
+		        		this.lastX, this.lastY);
+		        break;
+			case CLOSE:
+				ix = this.lastX;
+				iy = this.lastY;
+				this.lastX = this.moveX;
+				this.lastY = this.moveY;
+		        element = new PathElement2f.ClosePathElement2f(
+		        		ix, iy,
+		        		this.lastX, this.lastY);
+				break;
+			case QUAD_TO:
+			default:
+				throw new NoSuchElementException();
+			}
+			
+			assert(element!=null);
+			
+			++this.index;
+			
+			return element;
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return PathWindingRule.NON_ZERO;
+		}
+		
+	}
+
+	/** Iterator on the path elements of the rectangle.
+	 * 
+	 * @author $Author: sgalland$
+	 * @version $FullVersion$
+	 * @mavengroupid $GroupId$
+	 * @mavenartifactid $ArtifactId$
+	 */
+	private static class TransformPathIterator implements PathIterator2f {
+		
+		private final Transform2D transform;
+		private final float x;
+		private final float y;
+		private final float w;
+		private final float h;
+		private final float aw;
+		private final float ah;
+		private int index = 0;
+		
+		private float moveX, moveY;
+		private final Point2D last = new Point2f();
+		private final Point2D ctrl1 = new Point2f();
+		private final Point2D ctrl2 = new Point2f();
+		
+		/**
+		 * @param x
+		 * @param y
+		 * @param w
+		 * @param h
+		 * @param aw
+		 * @param ah
+		 * @param transform
+		 */
+		public TransformPathIterator(float x, float y, float w, float h, float aw, float ah, Transform2D transform) {
+			this.transform = transform;
+			this.x = x;
+			this.y = y;
+			this.w = Math.max(0f, w);
+			this.h = Math.max(0f, h);
+			this.aw = Math.min(Math.abs(aw), w);
+			this.ah = Math.min(Math.abs(ah), h);
+			if (this.w<=0f || this.h<=0f) {
+				this.index = TYPES.length;
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			return this.index<TYPES.length;
+		}
+		
+		@Override
+		public PathElement2f next() {
+			if (this.index>=TYPES.length) throw new NoSuchElementException();
+			int idx = this.index;
+
+			PathElement2f element = null;
+			PathElementType type = TYPES[idx];
+			float ctrls[] = CTRL_PTS[idx];
+			float ix, iy;
+			
+			switch(type) {
+			case MOVE_TO:
+				this.moveX = this.x + ctrls[0] * this.w + ctrls[1] * this.aw;
+				this.moveY = this.y + ctrls[2] * this.h + ctrls[3] * this.ah;
+				this.last.set(this.moveX, this.moveY);
+				this.transform.transform(this.last);
+		        element = new PathElement2f.MovePathElement2f(
+		        		this.last.getX(), this.last.getY());
+		        break;
+			case LINE_TO:
+				ix = this.last.getX();
+				iy = this.last.getY();
+				this.last.set(
+						this.x + ctrls[0] * this.w + ctrls[1] * this.aw,
+						this.y + ctrls[2] * this.h + ctrls[3] * this.ah);
+				this.transform.transform(this.last);
+		        element = new PathElement2f.LinePathElement2f(
+		        		ix, iy,
+		        		this.last.getX(), this.last.getY());
+		        break;
+			case CURVE_TO:
+				ix = this.last.getX();
+				iy = this.last.getY();
+				this.ctrl1.set(
+					this.x + ctrls[0] * this.w + ctrls[1] * this.aw,
+					this.y + ctrls[2] * this.h + ctrls[3] * this.ah);
+				this.transform.transform(this.ctrl1);
+				this.ctrl2.set(
+						this.x + ctrls[4] * this.w + ctrls[5] * this.aw,
+						this.y + ctrls[6] * this.h + ctrls[7] * this.ah);
+				this.transform.transform(this.ctrl2);
+				this.last.set(
+						this.x + ctrls[8] * this.w + ctrls[9] * this.aw,
+						this.y + ctrls[10] * this.h + ctrls[11] * this.ah);
+				this.transform.transform(this.last);
+		        element = new PathElement2f.CurvePathElement2f(
+		        		ix, iy,
+		        		this.ctrl1.getX(), this.ctrl1.getY(),
+		        		this.ctrl2.getX(), this.ctrl2.getY(),
+		        		this.last.getX(), this.last.getY());
+		        break;
+			case CLOSE:
+				ix = this.last.getX();
+				iy = this.last.getY();
+				this.last.set(this.moveX, this.moveY);
+				this.transform.transform(this.last);
+		        element = new PathElement2f.ClosePathElement2f(
+		        		ix, iy,
+		        		this.last.getX(), this.last.getY());
+				break;
+			case QUAD_TO:
+			default:
+				throw new NoSuchElementException();
+			}
+			
+			assert(element!=null);
+			
+			++this.index;
+			
+			return element;
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public PathWindingRule getWindingRule() {
+			return PathWindingRule.NON_ZERO;
+		}
+		
+	}
+
+}
\ No newline at end of file

Added: trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Segment2f.java
===================================================================
--- trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Segment2f.java	                        (rev 0)
+++ trunk/math/src/main/java/org/arakhne/afc/math/continous/object2d/Segment2f.java	2013-03-20 14:54:50 UTC (rev 388)
@@ -0,0 +1,804 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010-2013 Stephane GALLAND.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General P