Commits

Michael Ludwig committed 6ff2d4c

Remove concept of "canonical" vs "fast" component and separate them into Component and ComponentData classes. Clean up iterator infrastructure and make component data definition more customizable.

NOT FINISHED - FAILS COMPILATION.

Comments (0)

Files changed (54)

 Entreri, an entity-component framework in Java
 
-Copyright (c) 2011, Michael Ludwig
+Copyright (c) 2012, Michael Ludwig
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification, 

src/main/java/com/googlecode/entreri/AbstractController.java

     }
 
     @Override
-    public void onComponentAdd(Component c) {
+    public void onComponentAdd(ComponentData c) {
         // do nothing in base class
     }
 
     @Override
-    public void onComponentRemove(Component c) {
+    public void onComponentRemove(ComponentData c) {
         // do nothing in base class
     }
 }

src/main/java/com/googlecode/entreri/Component.java

-/*
- * Entreri, an entity-component framework in Java
- *
- * Copyright (c) 2011, Michael Ludwig
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *     Redistributions of source code must retain the above copyright notice,
- *         this list of conditions and the following disclaimer.
- *     Redistributions in binary form must reproduce the above copyright notice,
- *         this list of conditions and the following disclaimer in the
- *         documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
 package com.googlecode.entreri;
 
-import java.util.concurrent.ConcurrentHashMap;
-
 import com.googlecode.entreri.property.IndexedDataStore;
 import com.googlecode.entreri.property.Property;
-import com.googlecode.entreri.property.PropertyFactory;
-import com.googlecode.entreri.property.Unmanaged;
 
 /**
  * <p>
- * Component represents a grouping of reusable and related states that are added
+ * ComponentData represents a grouping of reusable and related states that are added
  * to an {@link Entity}. Components are intended to be data storage objects, so
  * their definition should not contain methods for processing or updating (that
  * is the responsibility of a {@link Controller}). Some Components may be
  * arguments when adding a new component to an Entity.
  * </p>
  * <p>
- * The behavior or purpose of a Component should be well defined, including its
+ * The behavior or purpose of a ComponentData should be well defined, including its
  * behavior with respect to other Components attached to the same Entity. It may
  * be that to function correctly or--more likely--usefully, related Components
  * will have to be used as well. An example of this might be a transform
  * component and a shape component for rendering.
  * </p>
  * <p>
- * Each Component class gets a {@link TypedId}, which can be looked up with
+ * Each ComponentData class gets a {@link TypeId}, which can be looked up with
  * {@link #getTypedId(Class)}, passing in the desired class type. Because the
  * entity-component design pattern does not follow common object-oriented
- * principles, certain rules are followed when handling Component types in a
+ * principles, certain rules are followed when handling ComponentData types in a
  * class hierarchy:
  * <ol>
- * <li>Any abstract type extending Component cannot get a TypedId</li>
- * <li>All concrete classes extending Component get separate TypedIds, even if
- * they extend from the same intermediate classes beneath Component.</li>
- * <li>All intermediate classes in a Component type's hierarchy must be abstract
+ * <li>Any abstract type extending ComponentData cannot get a TypeId</li>
+ * <li>All concrete classes extending ComponentData get separate TypedIds, even if
+ * they extend from the same intermediate classes beneath ComponentData.</li>
+ * <li>All intermediate classes in a ComponentData type's hierarchy must be abstract
  * or runtime exceptions will be thrown.</li>
  * </ol>
  * As an example, an abstract component could be Light, with concrete subclasses
  * SpotLight and DirectionLight. SpotLight and DirectionLight would be separate
- * component types as determined by TypedId. Light would not have any TypedId
+ * component types as determined by TypeId. Light would not have any TypeId
  * and only serves to consolidate property definition among related component
  * types.
  * </p>
  * themselves. See {@link #getTypedId(Class)} for the complete contract.
  * </p>
  * <p>
- * Component instances are tied to an index into the IndexedDataStores used by
+ * ComponentData instances are tied to an index into the IndexedDataStores used by
  * their properties. The index can be fetched by calling {@link #getIndex()}. An
- * instance of Component may have its index changed, effectively changing it to
+ * instance of ComponentData may have its index changed, effectively changing it to
  * a different "instance". This is most common when using the fast iterators.
  * Because of this, reference equality may not work, instead you should rely on
  * {@link #equals(Object)}.
  * </p>
+ * <p>
+ * Compone
  * 
  * @author Michael Ludwig
  */
-public abstract class Component {
-    // Use a ConcurrentHashMap to perform reads. It is still synchronized completely to do
-    // an insert to make sure a type doesn't try to use two different id values.
-    private static final ConcurrentHashMap<Class<? extends Component>, TypedId<? extends Component>> typeMap 
-        = new ConcurrentHashMap<Class<? extends Component>, TypedId<? extends Component>>();
-    private static final ConcurrentHashMap<TypedId<? extends Component>, ComponentBuilder<?>> builderMap
-        = new ConcurrentHashMap<TypedId<? extends Component>, ComponentBuilder<?>>();
+public final class Component<T extends ComponentData<T>> {
+    private final ComponentIndex<T> owner;
     
-    private static int idSeq = 0;
+    private int index;
+    private int version;
     
-    /**
-     * <var>index</var> is a sliding component index into the indexed data store
-     * for each property of the component. It can be mutated by the EntitySystem
-     * to effectively change the Component instance's values to another
-     * component in the system.
-     */
-    int index;
+    Component(ComponentIndex<T> owner, int index) {
+        this.owner = owner;
+        this.index = index;
+        this.version = 0;
+    }
     
-    final ComponentIndex<?> owner;
+    public T getData() {
+        T data = getEntitySystem().createDataInstance(getTypeId());
+        if (data.set(this))
+            return data;
+        else
+            return null; 
+    }
     
-    private final TypedId<? extends Component> typedId;
-
-    /**
-     * <p>
-     * Create a new Component instance that has its property data managed by the
-     * given EntitySystem. Multiple Component instances may represent the same
-     * "component" if their index's are the same.
-     * </p>
-     * <p>
-     * Subclasses must call this constructor with the arguments as passed-in and
-     * must not change them. Abstract subclasses can add additional arguments,
-     * but concrete subclasses must have the same constructor signatures except
-     * that it is private.
-     * </p>
-     * 
-     * @param system The owning EntitySystem of the Component
-     * @param index The initial index of this Component
-     * @throws NullPointerException if system is null
-     * @throws IllegalArgumentException if index is less than 0
-     */
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    protected Component(EntitySystem system, int index) {
-        if (system == null)
-            throw new NullPointerException("EntitySystem cannot be null");
-        if (index < 0)
-            throw new IllegalArgumentException("Index must be at least 0: " + index);
-        TypedId raw = getTypedId(getClass());
-
-        this.owner = system.getIndex(raw);
-        this.index = index;
-        typedId = raw;
+    public boolean isLive() {
+        return index != 0;
     }
-
-    /**
-     * <p>
-     * Called when the EntitySystem creates a new Component and has properly
-     * configured its declared properties. This is only called when the
-     * Component is being added to an Entity. This is not called when a new
-     * component instance is created for the purposes of a fast iterator
-     * (because it's just acting as a shell in that case), or being cloned from
-     * a template.
-     * </p>
-     * <p>
-     * The var-args initParams are the initial object parameters, in the same
-     * order as they were declared in the component's {@link InitParams}
-     * annotation. If the component does not define an InitParams annotation, no
-     * arguments are passed in. This will only be called after the EntitySystem
-     * has validated the proper type of each argument, although primitives will
-     * be boxed. Further validation, such as null checks, must be performed
-     * here.
-     * </p>
-     * <p>
-     * The InitParams annotation is inherited, so care must be given when
-     * extending an intermediate, abstract component type. Subclasses must be
-     * sure to call super with arguments matching its super-type's InitParams
-     * annotation.
-     * </p>
-     * <p>
-     * Note that in many cases the default value (usually 0 or null), assigned
-     * by the {@link PropertyFactory} that created the component's properties
-     * could be sufficient.
-     * </p>
-     * 
-     * @param initParams The initial parameters for the Component
-     */
-    protected abstract void init(Object... initParams) throws Exception;
     
-    /**
-     * <p>
-     * Return the unique TypedId associated with this Component's class type.
-     * All Components of the same class will return this id, too.
-     * </p>
-     * <p>
-     * It is recommended that implementations override this method to use the
-     * proper return type. Component does not perform this cast to avoid a
-     * parameterizing Component. Do not change the actual returned instance,
-     * though.
-     * </p>
-     * 
-     * @return The TypedId of this Component
-     */
-    public TypedId<? extends Component> getTypedId() {
-        return typedId;
+    public boolean isEnabled() {
+        // if isLive() returns false, index references the 0th index, which
+        // just contains garbage
+        return owner.isEnabled(index);
     }
-
-    /**
-     * Get the Entity that owns this Component. The Entity will still be part of
-     * an EntitySystem, and the component can be iterated over via
-     * {@link EntitySystem#iterator(TypedId)}. If a Component is removed from an
-     * Entity (or the Entity is removed from the system), this will return null.
-     * 
-     * @return The owning Entity
-     * @throws IndexOutOfBoundsException if the Component has been removed from
-     *             an Entity, or if its owning Entity has been removed from its
-     *             EntitySystem.
-     */
-    public final Entity getEntity() {
+    
+    public void setEnabled(boolean enable) {
+        // if isLive() returns false, index references the 0th index, which
+        // just contains garbage so this setter is safe
+        owner.setEnabled(index, enable);
+    }
+    
+    public Entity getEntity() {
+        // if isLive() returns false, then the entity index will also be 0,
+        // so getEntityByIndex() returns null, which is expected
         int entityIndex = owner.getEntityIndex(index);
         return owner.getEntitySystem().getEntityByIndex(entityIndex);
     }
-
-    /**
-     * Return the index of this Component within the IndexedDataStores that back
-     * the defined properties of a Component. A Component instance may have its
-     * index change if it is being used to slide over the component data (e.g.
-     * in a fast iterator).
-     * 
-     * @return The index of the component used to access its IndexedDataStores.
-     */
-    public final int getIndex() {
+    
+    public EntitySystem getEntitySystem() {
+        return owner.getEntitySystem();
+    }
+    
+    public TypeId<T> getTypeId() {
+        return owner.getTypeId();
+    }
+    
+    void setIndex(int index) {
+        this.index = index;
+        version++;
+    }
+    
+    int getIndex() {
         return index;
     }
-
-    /**
-     * @return True if this Component is still attached to an Entity, or false
-     *         if it has been removed
-     */
-    public final boolean isLive() {
-        return index != 0;
-    }
-
-    /**
-     * <p>
-     * Component's hashCode() returns the entity id of the component's owning
-     * entity. This means that any Component instance of this type that has the same index in
-     * the same EntitySystem will correctly use the same hash code.
-     * </p>
-     * <p>
-     * This means you can use the components created by a system's fast
-     * iterators to query a hash-based collections. However, you should never
-     * store fast components into a hash-based collection because their index
-     * (and thus hash code) will change each iteration.
-     * </p>
-     * <p>
-     * Additionally, a component's index is updated when it is removed from an
-     * entity or system. This means it is critical to remove components from
-     * collections before they a removed from a system. This can be done in
-     * {@link Controller#onComponentRemove(Component)}.
-     * </p>
-     * 
-     * @throws IllegalStateException if the component has already been removed
-     */
-    @Override
-    public int hashCode() {
-        if (!isLive())
-            throw new IllegalStateException("Component is not alive anymore");
-        return owner.getEntitySystem().getEntityId(owner.getEntityIndex(index));
-    }
-
-    /**
-     * <p>
-     * Component's equals() returns true if the object is another component of
-     * the same type, with the same owning Entity. This means that any component
-     * of this type that has the same index in the same entity system will
-     * correctly be treated as equal.
-     * </p>
-     * <p>
-     * This means you can use the components created by a system's fast
-     * iterators to query equals-based collections. However, you should never
-     * store fast components into a equals-based collections because their index
-     * (and thus definition of equality) will change with each iteration.
-     * </p>
-     * <p>
-     * Additionally, a component's index is updated when it is removed from an
-     * entity or system. This means it is critical to remove components from
-     * collections before they are removed from the system. This can be done in
-     * {@link Controller#onComponentRemove(Component)}.
-     * </p>
-     * 
-     * @param o The object to test equality with
-     * @return True if the two instances represent the same conceptual component
-     * @throws IllegalStateException if the component has already been removed
-     */
-    @Override
-    public boolean equals(Object o) {
-        if (!isLive())
-            throw new IllegalStateException("Component is not alive anymore");
-        
-        if (!(o instanceof Component))
-            return false;
-        Component c = (Component) o;
-        if (c.owner == owner) {
-            // We use the hash code, since it is either the owner's id (unchanging)
-            // or the cached id from just before it was removed
-            return hashCode() == c.hashCode();
-        } else {
-            // type and owner don't match
-            return false;
-        }
-    }
-
-    /**
-     * <p>
-     * Return the unique TypedId instance for the given <tt>type</tt>. If a
-     * TypedId hasn't yet been created a new one is instantiated with the next
-     * numeric id in the internal id sequence. The new TypedId is stored for
-     * later, so that subsequent calls to {@link #getTypedId(Class)} with
-     * <tt>type</tt> will return the same instance. It is recommended that a
-     * Component declare a static final <tt>ID</tt> holding its TypedId.
-     * </p>
-     * <p>
-     * This method also performs runtime checks to ensure the validity of the
-     * Component type definition. The following rules must be upheld or an
-     * {@link IllegalComponentDefinitionException} is thrown.
-     * <ul>
-     * <li>If the class extends from a class other than Component, that class
-     * must be a subclass of Component and be declared abstract. Additional
-     * rules might affect these parent classes.</li>
-     * <li>A concrete Component type must have only one constructor; it must be
-     * private and with arguments: EntitySystem, int. Abstract Component types
-     * do not have this restriction.</li>
-     * <li>Any non-static fields defined in a Component (abstract or concrete)
-     * must implement Property and be declared private or protected, or be
-     * annotated with {@link Unmanaged} (in which case the field is ignored.</li>
-     * </ul>
-     * Additionally, abstract Component types cannot have a TypedId assigned to
-     * them.
-     * </p>
-     * 
-     * @param <T> The Component class type
-     * @param type The Class whose TypedId is fetched, which must be a subclass
-     *            of Component
-     * @return A unique TypedId associated with the given type
-     * @throws NullPointerException if type is null
-     * @throws IllegalArgumentException if type is not actually a subclass of
-     *             Component, or if it is abstract
-     * @throws IllegalComponentDefinitionException if the type does not follow
-     *             the definition rules described above
-     * @throws SecurityException if the reflection needed to create and analyze
-     *             the Component fails
-     */
-    @SuppressWarnings("unchecked")
-    public static <T extends Component> TypedId<T> getTypedId(Class<T> type) {
-        if (type == null)
-            throw new NullPointerException("Type cannot be null");
-        
-        // Do a look up first without locking to avoid the synchronized lock and expensive
-        // error checking.  If we found one, we know it passed validation the first time, otherwise
-        // we'll validate it before creating a new TypedId.
-        TypedId<T> id = (TypedId<T>) typeMap.get(type);
-        if (id != null)
-            return id; // Found an existing id
-        
-        // Create a ComponentBuilder for the type - theoretically we could double-up
-        // on ComponentBuilder creation if the same type is requested, but that has no
-        // adverse consequences. The first builder will get stored for later
-        ComponentBuilder<T> builder = new ComponentBuilder<T>(type);
-        
-        synchronized(typeMap) {
-            // Must create a new id, we lock completely to prevent concurrent getTypedId() on the
-            // same type using two different ids.  One would get overridden and its returned TypedId
-            // would be invalid.
-            // - Double check, though, before creating a new id
-            id = (TypedId<T>) typeMap.get(type);
-            if (id != null)
-                return id; // Someone else put in the type after we checked but before we locked
-            
-            id = new TypedId<T>(type, idSeq++);
-            typeMap.put(type, id);
-            builderMap.put(id, builder);
-            return id;
-        }
-    }
     
-    @SuppressWarnings("unchecked")
-    static <T extends Component> ComponentBuilder<T> getBuilder(TypedId<T> id) {
-        // If they have the TypedId instance, then we already have created the builder
-        return (ComponentBuilder<T>) builderMap.get(id);
+    int getVersion() {
+        return version;
     }
 }

src/main/java/com/googlecode/entreri/ComponentBuilder.java

-/*
- * Entreri, an entity-component framework in Java
- *
- * Copyright (c) 2011, Michael Ludwig
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *     Redistributions of source code must retain the above copyright notice,
- *         this list of conditions and the following disclaimer.
- *     Redistributions in binary form must reproduce the above copyright notice,
- *         this list of conditions and the following disclaimer in the
- *         documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.googlecode.entreri;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.googlecode.entreri.property.AbstractPropertyFactory;
-import com.googlecode.entreri.property.Factory;
-import com.googlecode.entreri.property.Parameter;
-import com.googlecode.entreri.property.Parameters;
-import com.googlecode.entreri.property.Property;
-import com.googlecode.entreri.property.PropertyFactory;
-import com.googlecode.entreri.property.Unmanaged;
-
-/**
- * <p>
- * ComponentBuilder is a factory for creating new instances of Components of a
- * specific type. It is capable of using reflection to instantiate Property
- * instances for the Components declared property fields, based on the
- * {@link Factory}, {@link Parameters}, and {@link Parameter} annotations.
- * </p>
- * <p>
- * ComponentBuilder is thread safe, unlike the majority of the library, because
- * a single ComponentBuilder is used for each type, across all systems.
- * </p>
- * 
- * @author Michael Ludwig
- * @param <T> The built component type
- */
-final class ComponentBuilder<T extends Component> {
-    private final List<PropertyFactory<?>> propertyFactories;
-    private final Constructor<T> constructor;
-    private final List<Field> fields;
-
-    /**
-     * Create a new ComponentBuilder for the given type of Component. This is a
-     * slower constructor with lots of reflection so builders should be cached.
-     * This constructor also validates the component definition.
-     * 
-     * @param type The component type created by this builder
-     * @throws IllegalArgumentException if the class is not really a component
-     *             or if it is abstract
-     * @throws IllegalComponentDefinitionException if the class hierarchy of the
-     *             component type is invalid by breaking any of the constructor
-     *             or field rules for defining a component
-     */
-    @SuppressWarnings("unchecked")
-    public ComponentBuilder(Class<T> type) {
-        // Now we actually have to build up a new TypedId - which is sort of slow
-        if (!Component.class.isAssignableFrom(type))
-            throw new IllegalArgumentException("Type must be a subclass of Component: " + type);
-        
-        // Make sure we don't create TypedIds for abstract Component types 
-        // (we don't want to try to allocate these)
-        if (Modifier.isAbstract(type.getModifiers()))
-            throw new IllegalArgumentException("Component class type cannot be abstract: " + type);
-        
-        // Accumulate all property fields and validate type hierarchy
-        fields = new ArrayList<Field>(getFields(type));
-        
-        Class<? super T> parent = type.getSuperclass();
-        while(!Component.class.equals(parent)) {
-            if (!Modifier.isAbstract(parent.getModifiers()))
-                throw new IllegalComponentDefinitionException(type, "Parent class " + parent + " is not abstract");
-            
-            // this cast is safe since we're in the while loop
-            fields.addAll(getFields((Class<? extends Component>) parent));
-            parent = parent.getSuperclass();
-        }
-        
-        constructor = getConstructor(type);
-        propertyFactories = getPropertyFactories(fields);
-    }
-
-    /**
-     * Get the map from Fields of the component type to PropertyFactory
-     * implementations that will create valid property objects for each field.
-     * The created properties can then form a map valid with
-     * {@link #newInstance(EntitySystem, int, Map)}.
-     * 
-     * @return A map from field to property factory for the type associated with
-     *         this builder
-     */
-    public Map<Field, PropertyFactory<?>> getPropertyFactories() {
-        Map<Field, PropertyFactory<?>> props = new HashMap<Field, PropertyFactory<?>>();
-        for (int i = 0; i < propertyFactories.size(); i++)
-            props.put(fields.get(i), propertyFactories.get(i));
-        return Collections.unmodifiableMap(props);
-    }
-
-    /**
-     * <p>
-     * Create a new instance of the Component type created by this builder, for
-     * the given system. The component will use the given index initially, but
-     * its {@link Component#init()} method is NOT called. The map of properties
-     * is used to assign values to the declared property fields of the type.
-     * </p>
-     * <p>
-     * It is assumed that the map was created by the factories returned from
-     * {@link #getPropertyFactories()}. Additionally, it is assumed that
-     * {@link PropertyFactory#setValue(Property, int)} is invoked by the caller
-     * as appropriate (no initialization is performed by the builder).
-     * </p>
-     * 
-     * @param system The owning EntitySystem
-     * @param index The index of the new component in the system
-     * @param properties The map of properties used to assign field values for
-     *            the new component
-     * @return A new component of type T
-     * @throws RuntimeException if the properties weren't compatible with the
-     *             list returned by createProperties()
-     */
-    public T newInstance(EntitySystem system, int index, Map<Field, Property> properties) {
-        try {
-            T t = constructor.newInstance(system, index);
-            for (int i = 0; i < fields.size(); i++) {
-                fields.get(i).set(t, properties.get(fields.get(i)));
-            }
-            
-            return t;
-        } catch (Exception e) {
-            throw new RuntimeException("Unable to create new Component instance", e);
-        }
-    }
-    
-    private static <T extends Component> List<PropertyFactory<?>> getPropertyFactories(List<Field> fields) {
-        List<PropertyFactory<?>> factories = new ArrayList<PropertyFactory<?>>();
-        for (int i = 0; i < fields.size(); i++) {
-            factories.add(createFactory(fields.get(i)));
-        }
-        return factories;
-    }
-    
-    private static Object parseValue(Class<?> paramType, String paramValue, Class<? extends Component> forCType) {
-        try {
-            if (String.class.equals(paramType)) {
-                return paramValue;
-            } else if (Class.class.equals(paramType)) {
-                return Class.forName(paramValue);
-            } else if (int.class.equals(paramType) || Integer.class.equals(paramType)) {
-                return Integer.parseInt(paramValue);
-            } else if (float.class.equals(paramType) || Float.class.equals(paramType)) {
-                return Float.parseFloat(paramValue);
-            } else if (double.class.equals(paramType) || Double.class.equals(paramType)) {
-                return Double.parseDouble(paramValue);
-            } else if (long.class.equals(paramType) || Long.class.equals(paramType)) {
-                return Long.parseLong(paramValue);
-            } else if (short.class.equals(paramType) || Short.class.equals(paramType)) {
-                return Short.parseShort(paramValue);
-            } else if (byte.class.equals(paramType) || Byte.class.equals(paramType)) {
-                return Byte.parseByte(paramValue);
-            } else if (char.class.equals(paramType) || Character.class.equals(paramType)) {
-                return paramValue.charAt(0);
-            }
-        } catch(Exception e) {
-            throw new IllegalComponentDefinitionException(forCType, "Cannot convert parameter value, " + paramValue + ", to type: " + paramType);
-        }
-        
-        throw new IllegalComponentDefinitionException(forCType, "Unsupported parameter value type: " + paramType + ", it must be a String, Class, or (boxed) primitive");
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private static PropertyFactory<?> createFactory(Field field) {
-        Class<? extends Property> type = (Class<? extends Property>) field.getType();
-        Annotation[] annots = field.getAnnotations();
-        Class<? extends Component> forCType = (Class<? extends Component>) field.getDeclaringClass();
-        
-        Parameter[] params = new Parameter[0];
-        for (int i = 0; i < annots.length; i++) {
-            if (annots[i] instanceof Parameters) {
-                // take params array from the @Parameters annotation
-                params = ((Parameters) annots[i]).value();
-                break;
-            } else if (annots[i] instanceof Parameter) {
-                // take @Parameter annotation as single-arg constructor
-                params = new Parameter[] { (Parameter) annots[i] };
-                break;
-            } else if (annots[i] instanceof Factory) {
-                // use the declared PropertyFactory from the @Factory annotation
-                Factory fa = (Factory) annots[i];
-                
-                // verify that the PropertyFactory actually creates the right type
-                Method create;
-                try {
-                    create = fa.value().getMethod("create");
-                } catch (Exception e) {
-                    // should not happen
-                    throw new RuntimeException("Unable to inspect PropertyFactory create() method", e);
-                }
-                
-                if (!type.isAssignableFrom(create.getReturnType()))
-                    throw new IllegalComponentDefinitionException(forCType, "@Factory for " + fa.value() + " creates incorrect Property type for property type: " + type);
-                
-                PropertyFactory<?> factory;
-                try {
-                    factory = fa.value().newInstance();
-                } catch (Exception e) {
-                    throw new IllegalComponentDefinitionException(forCType, "Cannot create PropertyFactory from @Factory annotation: " + fa.value());
-                }
-                
-                return factory;
-            } // else unknown annotation so ignore it
-        }
-        
-        // At this point we need to be able to instantiate the Property with reflection
-        // so make sure it's not an abstract type (below we'll make sure we have a ctor)
-        if (Modifier.isAbstract(type.getModifiers()))
-            throw new IllegalComponentDefinitionException(forCType, "Property cannot be instantiated because its type is abstract: " + field);
-        
-        Class<?>[] ctorTypes = new Class<?>[params.length];
-        Object[] paramValues = new Object[params.length];
-        for (int i = 0; i < params.length; i++) {
-            ctorTypes[i] = params[i].type();
-            paramValues[i] = parseValue(ctorTypes[i], params[i].value(), forCType);
-        }
-        
-        try {
-            Constructor<?> ctor = type.getDeclaredConstructor(ctorTypes);
-            ctor.setAccessible(true); // just in case
-            return new ReflectionPropertyFactory(ctor, paramValues);
-        } catch(NoSuchMethodException e) {
-            // parameterized constructor does not exist
-            throw new IllegalComponentDefinitionException(forCType, "Property does not have a constructor matching: " + Arrays.toString(ctorTypes) + " for property " + field);
-        }
-    }
-    
-    @SuppressWarnings("unchecked")
-    private static <T extends Component> Constructor<T> getConstructor(Class<T> type) {
-        // This assumes that type is the concrete type, so it will fail if there
-        // are multiple constructors or it's not private with the correct arguments
-        Constructor<?>[] ctors = type.getDeclaredConstructors();
-        if (ctors.length != 1)
-            throw new IllegalComponentDefinitionException(type, "Component type must only define a single constructor");
-        
-        Constructor<T> ctor = (Constructor<T>) ctors[0];
-        if (!Modifier.isPrivate(ctor.getModifiers()) && !Modifier.isProtected(ctor.getModifiers()))
-            throw new IllegalComponentDefinitionException(type, "Component constructor must be private or protected");
-        
-        Class<?>[] args = ctor.getParameterTypes();
-        if (args.length != 2 || !EntitySystem.class.equals(args[0]) || !int.class.equals(args[1]))
-            throw new IllegalComponentDefinitionException(type, "Component constructor does not have proper signature of (ComponentIndex<T>, int, ...)");
-        
-        // Found it, now make it accessible (which might throw a SecurityException)
-        ctor.setAccessible(true);
-        return ctor;
-    }
-    
-    private static List<Field> getFields(Class<? extends Component> type) {
-        Field[] declared = type.getDeclaredFields();
-        List<Field> nonTransientFields = new ArrayList<Field>(declared.length);
-
-        for (int i = 0; i < declared.length; i++) {
-            int modifiers = declared[i].getModifiers();
-            if (Modifier.isStatic(modifiers))
-                continue; // ignore static fields
-            
-            if (declared[i].isAnnotationPresent(Unmanaged.class))
-                continue; // ignore the field
-            
-            if (!Property.class.isAssignableFrom(declared[i].getType())) {
-                throw new IllegalComponentDefinitionException(type, "Component has non-Property field that is not transient: " + declared[i]);
-            }
-            
-            if (!Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers))
-                throw new IllegalComponentDefinitionException(type, "Field must be private or protected: " + declared[i]);
-            
-            nonTransientFields.add(declared[i]);
-        }
-        
-        // Make sure all fields are accessible so we can assign them
-        AccessibleObject[] access = new AccessibleObject[nonTransientFields.size()];
-        for (int i = 0; i < access.length; i++)
-            access[i] = nonTransientFields.get(i);
-        Field.setAccessible(access, true);
-        return nonTransientFields;
-    }
-    
-    private static class ReflectionPropertyFactory<P extends Property> extends AbstractPropertyFactory<P> {
-        private final Constructor<P> ctor;
-        private final Object[] values;
-        
-        public ReflectionPropertyFactory(Constructor<P> ctor, Object[] values) {
-            this.ctor = ctor;
-            this.values = values;
-        }
-        
-        @Override
-        public P create() {
-            try {
-                return ctor.newInstance(values);
-            } catch (Exception e) {
-                throw new RuntimeException("Unexpected exception when creating Property, with constructor " + ctor);
-            }
-        }
-    }
-}

src/main/java/com/googlecode/entreri/ComponentData.java

+/*
+ * Entreri, an entity-component framework in Java
+ *
+ * Copyright (c) 2011, Michael Ludwig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *     Redistributions of source code must retain the above copyright notice,
+ *         this list of conditions and the following disclaimer.
+ *     Redistributions in binary form must reproduce the above copyright notice,
+ *         this list of conditions and the following disclaimer in the
+ *         documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.googlecode.entreri;
+
+import com.googlecode.entreri.property.ReflectionComponentDataFactory;
+
+
+/**
+ * <p>
+ * ComponentData is used to define types of components that can be added to
+ * entities. For performance reasons, the identity of a component is represented
+ * by instances of {@link Component}. ComponentData instances are used as views
+ * into the data of the components. This allows multiple instances to have their
+ * data packed together in primitive arrays or direct memory, allowing for
+ * significantly faster iteration.
+ * </p>
+ * <p>
+ * Additionally, by using a single ComponentData instance during the iteration,
+ * there is no need to follow the usual object references needed for each
+ * instance.
+ * </p>
+ * <p>
+ * ComponentData's are defined like any other class, but they are intended to be
+ * created and configured by a {@link ComponentDataFactory}. These factories may
+ * impose certain restrictions or requirements in what constructors or fields
+ * are valid.
+ * </p>
+ * 
+ * @see ReflectionComponentDataFactory
+ * @author Michael Ludwig
+ * @param <T> The self-referencing type of the ComponentData
+ */
+public abstract class ComponentData<T extends ComponentData<T>> {
+    private Component<T> ref;
+    private int version;
+    private int index;
+    
+    // this should be considered final, but is assigned in ComponentIndex
+    // to simplify implementation constructor requirements.
+    ComponentIndex<T> owner;
+    
+    protected ComponentData() { }
+    
+    /**
+     * Get the Entity that owns this ComponentData. The Entity will still be part of
+     * an EntitySystem, and the component can be iterated over via
+     * {@link EntitySystem#iterator(TypeId)}. If a ComponentData is removed from an
+     * Entity (or the Entity is removed from the system), this will return null.
+     * 
+     * @return The owning Entity
+     * @throws IndexOutOfBoundsException if the ComponentData has been removed from
+     *             an Entity, or if its owning Entity has been removed from its
+     *             EntitySystem.
+     */
+    public final Entity getEntity() {
+        int entityIndex = owner.getEntityIndex(index);
+        return owner.getEntitySystem().getEntityByIndex(entityIndex);
+    }
+
+    /**
+     * Return the index of this ComponentData within the IndexedDataStores that
+     * back the defined properties of a ComponentData. A ComponentData's index
+     * will change as calls to {@link #set(Component)} are made.
+     * 
+     * @return The index of the component used to access its IndexedDataStores.
+     */
+    public final int getIndex() {
+        return index;
+    }
+
+    /**
+     * <p>
+     * Return whether or not this ComponentData is still attached to the last
+     * Component passed into {@link #set(Component)}, and that that component is
+     * still live.
+     * </p>
+     * <p>
+     * It is possible for a ComponentData's component to be invalidated
+     * underneath it. This happens if the component or its owning entity is
+     * removed from the system, or if the entity system is
+     * {@link EntitySystem#compact() compacted}. Since this library is meant to
+     * be single-threaded (or externally synchronized), this should be
+     * predictable.
+     * </p>
+     * 
+     * @return True if this ComponentData is attached to the data of a Component
+     *         that is still live
+     */
+    public final boolean isValid() {
+        return ref != null && ref.getVersion() == version && index != 0;
+    }
+
+    /**
+     * Return whether or not the component this data is attached to is enabled.
+     * This is an optimized shortcut for <code>getComponent().isEnabled()</code>
+     * 
+     * @return True if the component is enabled
+     */
+    public final boolean isEnabled() {
+        return owner.isEnabled(index);
+    }
+
+    /**
+     * Set whether or not the component this data is attached to is enabled.
+     * This is an optimized shortcut for
+     * <code>getComponent().setEnabled(enable)</code>
+     * 
+     * @param enable True if the component should be enabled
+     */
+    public final void setEnabled(boolean enable) {
+        owner.setEnabled(index, enable);
+    }
+
+    /**
+     * Return the Component that this data reads and writes to. If
+     * {@link #isValid()} returns false, the returned Component is undefined. It
+     * may be the proper component, another component in the system, or null.
+     * 
+     * @return The component this data is attached to
+     */
+    public final Component<T> getComponent() {
+        return owner.getComponent(index);
+    }
+
+    /**
+     * <p>
+     * Set this ComponentData to read and write from the given Component. If the
+     * component reference is a non-null, live component, this ComponentData
+     * will be considered a valid ComponentData. While valid, its defined
+     * accessors and mutators will affect the property state of
+     * <tt>component</tt>.
+     * </p>
+     * <p>
+     * Invoking set() with another Component will shift this data to the new
+     * component, allowing it to mutate that.
+     * </p>
+     * <p>
+     * The ComponentData will remain valid until an action is taken that would
+     * invalidate the data or its component. At the moment, the only actions
+     * capable of this are removing the component or its entity from the system,
+     * or invoking {@link EntitySystem#compact()}.
+     * </p>
+     * 
+     * @param component The component this data should point to
+     * @return True if the data is now valid
+     * @throws IllegalArgumentException if component was not created by the same
+     *             entity system
+     */
+    public final boolean set(Component<T> component) {
+        if (component.getEntitySystem() != owner.getEntitySystem())
+            throw new IllegalArgumentException("Component not created by expected EntitySystem");
+        
+        this.ref = component;
+        if (ref != null) {
+            // if ref is not live, it's index should have been updated to 0
+            // so the component data will appear invalid as well
+            index = ref.getIndex();
+            version = ref.getVersion();
+        } else {
+            index = 0;
+            version = 0;
+        }
+        
+        return index != 0;
+    }
+
+    /**
+     * A slightly faster method that requires only an index to a component, and
+     * performs no validation.
+     * 
+     * @param componentIndex The index of the component
+     * @return True if the index is not 0
+     */
+    boolean setFast(int componentIndex) {
+        ref = owner.getComponent(componentIndex);
+        index = componentIndex;
+        version = (ref == null ? 0 : ref.getVersion());
+        return index != 0;
+    }
+}

src/main/java/com/googlecode/entreri/ComponentDataFactory.java

+package com.googlecode.entreri;
+
+import java.util.Map;
+
+import com.googlecode.entreri.property.Property;
+import com.googlecode.entreri.property.PropertyFactory;
+import com.googlecode.entreri.property.ReflectionComponentDataFactory;
+
+/**
+ * <p>
+ * ComponentDataFactory is a factory interface used to create instances of
+ * ComponentData to provide a flexible means to instantiate and configure
+ * ComponentData's for a specific type of component. For most purposes, the
+ * default {@link ReflectionComponentDataFactory} will be sufficient, unless the
+ * conventions enforced by it are too restrictive.
+ * </p>
+ * <p>
+ * The main purpose of the ComponentDataFactory is to act as the glue between
+ * the set of Properties representing all of the components in a system, and the
+ * ComponentData instances used to efficiently access their values in a clean
+ * manner.
+ * </p>
+ * <p>
+ * ComponentDataFactory implementations must be thread safe, which should not be
+ * difficult because their state is usually immutable.
+ * </p>
+ * 
+ * @author Michael Ludwig
+ * @param <T> The type of ComponentData created by the factory
+ */
+public interface ComponentDataFactory<T extends ComponentData<T>> {
+    /**
+     * <p>
+     * Return the named PropertyFactories that can be used to create all
+     * required Properties when configuring a new instance. The key of the map
+     * should be the same key that is specified when
+     * {@link #setProperty(ComponentData, String, Property)} is called.
+     * </p>
+     * <p>
+     * An example of the keys might be the field names declared in the class.
+     * </p>
+     * 
+     * @return The PropertyFactories created by this builder
+     */
+    public Map<String, PropertyFactory<?>> getPropertyFactories();
+
+    /**
+     * Construct a new instance of T that has not been configured. This means it
+     * should not have any assigned properties, and to expect subsequent calls
+     * to {@link #setProperty(ComponentData, String, Property)} to configure it.
+     * 
+     * @return A new instance
+     */
+    public T createInstance();
+
+    /**
+     * Inject the given property into the instance, where the property is
+     * assumed to have been constructed by PropertyFactory from
+     * {@link #getPropertyFactories()} that is stored by <tt>key</tt>.
+     * 
+     * @param instance The instance to configure
+     * @param key The key to the creating PropertyFactory or source of the
+     *            property
+     * @param property The property instance to inject
+     * @throws NullPointerException if any argument is null
+     */
+    public void setProperty(T instance, String key, Property property);
+    
+    // FIXME: we can generalize this to storing all data of a component, so 
+    // someone could choose to use a system not tied to the property interface,
+    // I'm not sure what exactly would need to change, since I'd want to still
+    // support decorating of component types.
+    // FIXME: is that really useful, too? They can already change the IndexedDataStore 
+    // used for a lot of flexibility.  I will ponder on it.
+}

src/main/java/com/googlecode/entreri/ComponentIndex.java

  */
 package com.googlecode.entreri;
 
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
 
+import com.googlecode.entreri.property.BooleanProperty;
 import com.googlecode.entreri.property.CompactAwareProperty;
 import com.googlecode.entreri.property.IndexedDataStore;
 import com.googlecode.entreri.property.Property;
 import com.googlecode.entreri.property.PropertyFactory;
 
 /**
- * ComponentIndex manages storing all the components of a specific type for an
+ * ComponentIndex manages storing all the componentDatas of a specific type for an
  * EntitySystem. It also controls the IndexedDataStore's for the type's set of
  * properties. It is package-private because its details are low-level and
  * complex.
  * @author Michael Ludwig
  * @param <T> The type of component stored by the index
  */
-final class ComponentIndex<T extends Component> {
+final class ComponentIndex<T extends ComponentData<T>> {
+    private final EntitySystem system;
+    private final TypeId<T> type;
+
+    private final ComponentDataFactory<T> factory;
+    
     // These three arrays have a special value of 0 or null stored in the 0th
-    // index, which allows us to lookup components or entities when they
+    // index, which allows us to lookup componentDatas or entities when they
     // normally aren't attached.
     private int[] entityIndexToComponentIndex;
     private int[] componentIndexToEntityIndex;
-    private Component[] components;
+    private Component<T>[] components;
+    private int componentInsert;
     
-    private int componentInsert;
-
     private final List<PropertyStore<?>> declaredProperties;
     private final List<PropertyStore<?>> decoratedProperties;
     
-    private final ComponentBuilder<T> builder;
-    private final Map<Field, Property> builderProperties; // Properties from declaredProperties, cached for newInstance()
-    private final Class<?>[] initParamTypes; // all primitives will be boxed at this point
-    
-    private final EntitySystem system;
-    
-    private final Comparator<Component> entityIndexComparator;
-
+    private final BooleanProperty enabledProperty; // this is also contained in decoratedProperties
+     
     /**
      * Create a ComponentIndex for the given system, that will store Components
      * of the given type.
      * @throws NullPointerException if system or type are null
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    public ComponentIndex(EntitySystem system, TypedId<T> type) {
+    public ComponentIndex(EntitySystem system, TypeId<T> type, ComponentDataFactory<T> factory) {
         if (system == null || type == null)
             throw new NullPointerException("Arguments cannot be null");
         
         this.system = system;
-        initParamTypes = getInitParams(type.getType());
+        this.factory = factory;
+        this.type = type;
         
-        builder = Component.getBuilder(type);
-        
-        Map<Field, PropertyFactory<?>> builderPropertyFactories = builder.getPropertyFactories();
-        builderProperties = new HashMap<Field, Property>();
+        Map<String, PropertyFactory<?>> propertyFactories = factory.getPropertyFactories();
         
         declaredProperties = new ArrayList<PropertyStore<?>>();
         decoratedProperties = new ArrayList<PropertyStore<?>>(); // empty for now
-        for (Entry<Field, PropertyFactory<?>> e: builderPropertyFactories.entrySet()) {
-            PropertyStore store = new PropertyStore(e.getValue());
+        for (Entry<String, PropertyFactory<?>> e: propertyFactories.entrySet()) {
+            PropertyStore store = new PropertyStore(e.getValue(), e.getKey());
             declaredProperties.add(store);
-            builderProperties.put(e.getKey(), store.property);
         }
         
         entityIndexToComponentIndex = new int[1]; // holds default 0 value in 0th index
         
         componentInsert = 1;
         
-        entityIndexComparator = new Comparator<Component>() {
-            @Override
-            public int compare(Component o1, Component o2) {
-                if (o1 != null && o2 != null)
-                    return componentIndexToEntityIndex[o1.index] - componentIndexToEntityIndex[o2.index];
-                else if (o1 != null)
-                    return -1; // push null o2 to end of array
-                else if (o2 != null)
-                    return 1; // push null o1 to end of array
-                else
-                    return 0; // both null so they are "equal"
-            }
-        };
-        
         // Make sure properties' stores hold enough space
         resizePropertyStores(declaredProperties, 1);
+        
+        // decorate the component data with a boolean property to track enabled status
+        enabledProperty = decorate(BooleanProperty.factory(1));
     }
     
-    private static Class<?>[] getInitParams(Class<? extends Component> type) {
-        InitParams params = type.getAnnotation(InitParams.class);
-        if (params == null)
-            return new Class<?>[0];
-        
-        Class<?>[] declaredTypes = params.value();
-        Class<?>[] boxedTypes = new Class<?>[declaredTypes.length];
-        for (int i = 0; i < declaredTypes.length; i++) {
-            if (int.class.equals(declaredTypes[i]))
-                boxedTypes[i] = Integer.class;
-            else if (short.class.equals(declaredTypes[i]))
-                boxedTypes[i] = Short.class;
-            else if (byte.class.equals(declaredTypes[i]))
-                boxedTypes[i] = Byte.class;
-            else if (long.class.equals(declaredTypes[i]))
-                boxedTypes[i] = Long.class;
-            else if (float.class.equals(declaredTypes[i]))
-                boxedTypes[i] = Float.class;
-            else if (double.class.equals(declaredTypes[i]))
-                boxedTypes[i] = Double.class;
-            else if (boolean.class.equals(declaredTypes[i]))
-                boxedTypes[i] = Boolean.class;
-            else if (char.class.equals(declaredTypes[i]))
-                boxedTypes[i] = Character.class;
-            else
-                boxedTypes[i] = declaredTypes[i];
-        }
-        return boxedTypes;
+    /**
+     * @return The type of component data stored by this component index
+     */
+    public TypeId<T> getTypeId() {
+        return type;
     }
-
+    
     /**
-     * @return An estimate on the number of components in the index, cannot be
+     * @return An estimate on the number of components in the index, will not be
      *         less than the true size
      */
     public int getSizeEstimate() {
 
     /**
      * Ensure that this ComponentIndex has enough internal space to hold its
-     * entity to component mapping for the given number of entities.
+     * entity-to-component mapping for the given number of entities.
      * 
      * @param numEntities The new number of entities
      */
             entityIndexToComponentIndex = Arrays.copyOf(entityIndexToComponentIndex, (int) (numEntities * 1.5f) + 1);
         }
     }
+
+    /**
+     * @param componentIndex The component to look up
+     * @return True if the component at componentIndex is enabled
+     */
+    public boolean isEnabled(int componentIndex) {
+        return enabledProperty.get(componentIndex, 0);
+    }
+
+    /**
+     * Set whether or not the component at <tt>componentIndex</tt> is enabled.
+     * 
+     * @param componentIndex The component index
+     * @param enabled True if the component is enabled
+     */
+    public void setEnabled(int componentIndex, boolean enabled) {
+        enabledProperty.set(enabled, componentIndex, 0);
+    }
     
     /*
      * As expandEntityIndex() but expands all related component data and arrays
-     * to hold the number of components. This doesn't need to be public so its hidden.
+     * to hold the number of components.
      */
     private void expandComponentIndex(int numComponents) {
         if (numComponents < components.length)
     }
     
     /**
-     * @param entityIndex The entity index whose component is fetched
-     * @return The canonical component instance attached to the given entity
-     *         index, or null if no component is attached yet
+     * @param componentIndex The component index whose component is fetched
+     * @return The component reference at the given index, may be null
      */
-    @SuppressWarnings("unchecked")
-    public T getComponent(int entityIndex) {
-        return (T) components[entityIndexToComponentIndex[entityIndex]];
+    public Component<T> getComponent(int componentIndex) {
+        return components[componentIndex];
     }
 
     /**
-     * Create a new component of this index's type and attach to it the entity
-     * at the given entity index, the new component will have its values copied
-     * from the existing template.
+     * Create a new component and attach to it the entity at the given entity
+     * index, the new component will have its values copied from the existing
+     * template.
      * 
      * @param entityIndex The entity index which the component is attached to
      * @param fromTemplate A template to assign values to the new component
      * @return A new component of type T
      * @throws NullPointerException if fromTemplate is null
+     * @throws IllegalArgumentException if the template was not created by this
+     *             index
+     * @throws IllegalStateException if the template is not live
      */
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    public T addComponent(int entityIndex, T fromTemplate) {
-        T instance = addComponent(entityIndex);
-
-        // Copy values from fromTemplate's properties to the new instances
-        List<PropertyStore<?>> templateProps = fromTemplate.owner.declaredProperties;
-        for (int i = 0; i < templateProps.size(); i++) {
-            PropertyStore src = templateProps.get(i);
-            PropertyStore dst = declaredProperties.get(i);
-            
-            src.clone(fromTemplate.index, dst.property, instance.index);
+    public Component<T> addComponent(int entityIndex, Component<T> fromTemplate) {
+        if (fromTemplate.getEntitySystem() != getEntitySystem())
+            throw new IllegalArgumentException("Component not owned by expected EntitySystem");
+        if (fromTemplate.getTypeId().equals(type))
+            throw new IllegalArgumentException("Component not of expected type, expected: " + type + ", but was: " + type);
+        if (!fromTemplate.isLive())
+            throw new IllegalStateException("Template component is not live");
+        
+        Component<T> instance = addComponent(entityIndex);
+        for (int i = 0; i < declaredProperties.size(); i++) {
+            PropertyStore store = declaredProperties.get(i);
+            store.clone(fromTemplate.getIndex(), store.property, instance.getIndex());
         }
         
         // fire add-event listener after cloning is completed
     }
 
     /**
-     * Create a new component of this index's type and attach to it the entity
-     * at the given entity index, the new component will be initialized with the
-     * given init parameters.
+     * Create a new component and attach to it the entity at the given entity
+     * index. The component will have the default state as specified by its
+     * properties.
      * 
      * @param entityIndex The entity index which the component is attached to
      * @param initParams The var-args of parameters that must match the
      * @return A new component of type T
      * @throws IllegalArgumentException if initParams is incorrect
      */
-    public T addComponent(int entityIndex, Object... initParams) {
-        // validate input
-        if (initParams == null)
-            initParams = new Object[0];
-        
-        boolean valid = true;
-        if (initParams.length == this.initParamTypes.length) {
-            for (int i = 0; i < initParams.length; i++) {
-                if (!this.initParamTypes[i].isInstance(initParams[i])) {
-                    valid = false;
-                    break;
-                }
-            }
-        } else {
-            valid = false;
-        }
-
-        if (!valid)
-            throw new IllegalArgumentException("Must provide init params in the order: " + Arrays.toString(this.initParamTypes));
-
-        // We know the arguments types match, so continue
-        T instance = addComponent(entityIndex);
-        
-        try {
-            // Pass parameters in as-is
-            instance.init(initParams);
-        } catch(Exception e) {
-            // initialization failed, so remove the created entity
-            removeComponent(entityIndex);
-            throw new IllegalArgumentException("Init parameters failed validation", e);
-        }
+    public Component<T> addComponent(int entityIndex) {
+        Component<T> instance = allocateComponent(entityIndex);
         
         // fire add-event listener after initialization is completed
         system.getControllerManager().fireComponentAdd(instance);
     /*
      * Allocate and store a new component, but don't initialize it yet.
      */
-    private T addComponent(int entityIndex) {
+    private Component<T> allocateComponent(int entityIndex) {
         if (entityIndexToComponentIndex[entityIndex] != 0)
             removeComponent(entityIndex);
         
         if (componentIndex >= components.length)
             expandComponentIndex(componentIndex + 1);
 
-        T instance = newInstance(componentIndex);
+        Component<T> instance = new Component<T>(this, componentIndex);
         components[componentIndex] = instance;
         componentIndexToEntityIndex[componentIndex] = entityIndex;
         entityIndexToComponentIndex[entityIndex] = componentIndex;
     }
 
     /**
+     * Create a new ComponentData of type T that can be used to view components
+     * in this index.
+     * 
+     * @return A new data instance
+     */
+    public T createDataInstance() {
+        // create a new instance from the factory - it will be completely detached
+        T t = factory.createInstance();
+        
+        // attach it to this data index, at the 0th index
+        //  - at this point the ComponentData's owner should be considered final
+        t.owner = this;
+        
+        // assign all property values
+        for (int i = 0; i < declaredProperties.size(); i++) {
+            PropertyStore<?> p = declaredProperties.get(i);
+            factory.setProperty(t, p.key, p.property);
+        }
+        
+        t.set(null);
+        return t;
+    }
+
+    /**
      * Detach or remove any component of this index's type from the entity with
      * the given index. True is returned if a component was removed, or false
      * otherwise.
         int componentIndex = entityIndexToComponentIndex[entityIndex];
 
         // This code works even if componentIndex is 0
-        Component oldComponent = components[componentIndex];
+        Component<T> oldComponent = components[componentIndex];
         if (oldComponent != null) {
             // perform component clean up before data is invalidated
             system.getControllerManager().fireComponentRemove(oldComponent);
-            oldComponent.index = 0;
+            oldComponent.setIndex(0);
         }
 
         components[componentIndex] = null;
      * Update all component data in the list of properties. If possible the data
      * store in swap is reused.
      */
-    private void update(List<PropertyStore<?>> properties, Component[] newToOldMap) {
+    private void update(List<PropertyStore<?>> properties, Component<T>[] newToOldMap) {
         for (int i = 0; i < properties.size(); i++) {
             PropertyStore<?> p = properties.get(i);
             IndexedDataStore origStore = p.property.getDataStore();
      * newToOldMap.
      */
     private IndexedDataStore update(IndexedDataStore src, IndexedDataStore dst, 
-                                    Component[] newToOldMap) {
+                                    Component<T>[] newToOldMap) {
         int dstSize = newToOldMap.length;
         
         if (dst == null || dst.size() < dstSize)
         int copyIndexOld = -1;
         for (i = 1; i < componentInsert; i++) {
             if (newToOldMap[i] == null) {
-                // we've hit the end of existing components, so break
+                // we've hit the end of existing componentDatas, so break
                 break;
             }
             
     /**
      * <p>
      * Compact the data of this ComponentIndex to account for removals and
-     * additions to the index. This will ensure that all active components are
+     * additions to the index. This will ensure that all active componentDatas are
      * packed into the underlying arrays, and that they will be accessed in the
      * same order as iterating over the entities directly.
      * </p>
      * @param numEntities The number of entities that are in the system
      */
     public void compact(int[] entityOldToNewMap, int numEntities) {
-        // First sort the canonical components array
-        Arrays.sort(components, 1, componentInsert, entityIndexComparator);
+        // First sort the canonical componentDatas array
+        Arrays.sort(components, 1, componentInsert, new Comparator<Component<T>>() {
+            @Override
+            public int compare(Component<T> o1, Component<T> o2) {
+                if (o1 != null && o2 != null)
+                    return componentIndexToEntityIndex[o1.getIndex()] - componentIndexToEntityIndex[o2.getIndex()];
+                else if (o1 != null)
+                    return -1; // push null o2 to end of array
+                else if (o2 != null)
+                    return 1; // push null o1 to end of array
+                else
+                    return 0; // both null so they are "equal"
+            }
+        });
         
-        // Update all of the property stores to match up with the components new positions
+        // Update all of the property stores to match up with the componentDatas new positions
         update(declaredProperties, components);
         update(decoratedProperties, components);
         
         int[] newComponentIndex = new int[components.length];
         for (int i = 1; i < components.length; i++) {
             if (components[i] != null) {
-                newComponentIndex[i] = entityOldToNewMap[componentIndexToEntityIndex[components[i].index]];
-                components[i].index = i;
+                newComponentIndex[i] = entityOldToNewMap[componentIndexToEntityIndex[components[i].getIndex()]];
+                components[i].setIndex(i);
                 componentInsert = i + 1;
             }
         }
     }
 
     /**
-     * @return An iterator over the canonical components in the index. The
-     *         iterator's remove() detaches the component from the entity
+     * @return An iterator over the components in the index. The iterator's
+     *         remove() detaches the component from the entity
      */
-    public Iterator<T> iterator() {
+    public Iterator<Component<T>> iterator() {
         return new ComponentIterator();
     }
 
     /**
-     * @return An iterator over the components of the index, but a single
-     *         component instance is reused. remove() detaches the current
-     *         component from the entity
-     */
-    public Iterator<T> fastIterator() {
-        return new FastComponentIterator();
-    }
-
-    /**
-     * Create a new instance of T that will take its data from the given index.
-     * The init() method of the Component is not called.
-     * 
-     * @param index The component index to wrap
-     * @return The new instance wrapping the data at the given index
-     */
-    public T newInstance(int index) {
-        return builder.newInstance(system, index, builderProperties);
-    }
-
-    /**
      * Decorate the type information of this ComponentIndex to add a property
      * created by the given factory. The returned property will have default
      * data assigned for each current Component in the index, and will have the
         int size = (declaredProperties.isEmpty() ? componentInsert
                                                  : declaredProperties.get(0).property.getDataStore().size());
         
-        PropertyStore<P> pstore = new PropertyStore<P>(factory);
+        PropertyStore<P> pstore = new PropertyStore<P>(factory, "decorated");
 
         // Set values from factory to all component slots
         IndexedDataStore newStore = pstore.property.getDataStore().create(size);
     }
     
     /*
-     * An iterator implementation over the canonical components of the index.
+     * An iterator implementation over the canonical componentDatas of the index.
      */
-    private class ComponentIterator implements Iterator<T> {
+    private class ComponentIterator implements Iterator<Component<T>> {
         private int index;
         private boolean advanced;
         
         }
 
         @Override
-        @SuppressWarnings("unchecked")
-        public T next() {
+        public Component<T> next() {
             if (!hasNext())
                 throw new NoSuchElementException();
             advanced = false;
-            return (T) components[index];
+            return components[index];
         }
 
         @Override
         public void remove() {
             if (advanced || index == 0)
                 throw new IllegalStateException("Must call next() before remove()");
-            if (components[index] == null)
-                throw new IllegalStateException("Component already removed");
+            if (componentIndexToEntityIndex[index] == 0)
+                throw new IllegalStateException("ComponentData already removed");
             removeComponent(componentIndexToEntityIndex[index]);
         }
         
         private void advance() {
             index++; // always advance at least 1
-            while(index < components.length && components[index] == null) {
+            while(index < components.length && componentIndexToEntityIndex[index] == 0) {
                 index++;
             }
             advanced = true;
     }
 
     /*
-     * An iterator over the components of the system that reuses a single
-     * instance for performance.
+     * Type wrapping a key, property, and factory, as well as an auxiliary data
+     * store for compaction.
      */
-    private class FastComponentIterator implements Iterator<T> {
-        private final T instance;
-        
-        private int index;
-        private boolean advanced;
-        
-        public FastComponentIterator() {
-            instance = newInstance(0);
-            index = 0;
-            advanced = false;
-        }
-        
-        @Override
-        public boolean hasNext() {
-            if (!advanced)
-                advance();
-            return index < componentInsert;
-        }
-
-        @Override
-        public T next() {
-            if (!hasNext())
-                throw new NoSuchElementException();
-            advanced = false;
-            instance.index = index;
-            return instance;
-        }
-
-        @Override
-        public void remove() {
-            if (advanced || index == 0)
-                throw new IllegalStateException("Must call next() before remove()");
-            
-            int entityIndex = componentIndexToEntityIndex[index];
-            if (entityIndex == 0)
-                throw new IllegalStateException("Component already removed");
-            
-            removeComponent(entityIndex);
-        }
-        
-        private void advance() {
-            // Check componentIndexToEntityIndex so we don't pull in an instance 
-            // and we can just iterate along the int[] array. A 0 value implies that
-            // the component does not have an attached entity, and has been removed
-            
-            index++; // always advance
-            while(index < componentIndexToEntityIndex.length && 
-                  componentIndexToEntityIndex[index] == 0) {
-                index++;
-            }
-            advanced = true;
-        }
-    }
-    
     private static class PropertyStore<P extends Property> {
+        final String key;
         final P property;
         final PropertyFactory<P> creator;
         IndexedDataStore swap; // may be null
         
         
-        public PropertyStore(PropertyFactory<P> creator) {
+        public PropertyStore(PropertyFactory<P> creator, String key) {
             this.creator = creator;
+            this.key = key;
             property = creator.create();
         }
         

src/main/java/com/googlecode/entreri/ComponentIterator.java

+package com.googlecode.entreri;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ComponentIterator {
+    private final List<ComponentData<?>> required;
+    private final List<ComponentData<?>> optional;
+    
+    private final EntitySystem system;
+    
+    private int index;
+    // FIXME: do we also store the shortest component type?
+    // FIXME: should I just use the iterator's over component type?
+    // FIXME: if not, can I remove them?
+    
+    public ComponentIterator(EntitySystem system) {
+        if (system == null)
+            throw new NullPointerException("System cannot be null");
+        this.system = system;
+        required = new ArrayList<ComponentData<?>>();
+        optional = new ArrayList<ComponentData<?>>();
+    }
+
+    public ComponentIterator addRequired(ComponentData<?> data) {
+        return add(data, required);
+    }
+    
+    public ComponentIterator addOptional(ComponentData<?> data) {
+        return add(data, optional);
+    }
+    
+    private ComponentIterator add(ComponentData<?> data, List<ComponentData<?>> list) {
+        
+    }
+    
+    public boolean next() {
+        
+    }
+    
+    public void reset() {
+        
+    }
+}

src/main/java/com/googlecode/entreri/Controller.java

     
     public void onEntityRemove(Entity e);
     
-    public void onComponentAdd(Component c);
+    public void onComponentAdd(Component<?> c);
     
-    public void onComponentRemove(Component c);
+    public void onComponentRemove(Component<?> c);
+    
+    // FIXME: these interfaces are going to have to be changed, I would like to
+    // ensure that a controller is limited to a single system.  This might 
+    // require having Controller be an abstract class with some setSystem() logic, etc.
+    
+    // FIXME: part of this is because the amount of work to store system specific
+    // data into the CM's data store is super tedious if a plain field would work.
+    
+    // THe CM's data sharing works fine across controllers, although I will have to
+    // update the scene system to store things as collections instead of as certain
+    // components.
+    
+    // FIXME: adding profiling would be pretty cool too.
+    
+    // FIXME: REVIEW: Do we want to keep the phases for controllers? Is it valuable, useful?
 }