public Object instance(Object[] parameters, Object[] localProducts) {
    if (this.collectionKind == CollectionKind.ARRAY) {
      Object array =
          Array.newInstance(
              this.collectionArgumentType.getComponentType(),
              this.collectionContentFactories.size());
      for (int i = 0; i < this.collectionContentFactories.size(); i++) {
        Array.set(
            array, i, this.collectionContentFactories.get(i).instance(parameters, localProducts));
      }
      return array;
    } else if (this.collectionKind == CollectionKind.LIST) {
      List<Object> list = new ArrayList<Object>();
      for (LocalFactory contentFactory : this.collectionContentFactories) {
        list.add(contentFactory.instance(parameters, localProducts));
      }
      return list;
    } else if (this.collectionKind == CollectionKind.SET) {
      Set<Object> set = new HashSet<Object>();
      for (LocalFactory contentFactory : this.collectionContentFactories) {
        set.add(contentFactory.instance(parameters, localProducts));
      }
      return set;
    }

    return null;
  }
  protected GlobalFactory<?> buildGlobalFactory(Container container, FactoryDefinition definition) {
    GlobalFactoryBase globalFactory = null;

    LocalFactory instantiationFactory = buildLocalFactoryRecursively(container, definition);
    definition.setLocalProductType(definition.getName(), instantiationFactory.getReturnType());

    if (definition.isNewInstance() || definition.isLocalizedMap()) {
      globalFactory = new GlobalNewInstanceFactory();
    } else if (definition.isSingleton()) {
      globalFactory = new GlobalSingletonFactory();
    } else if (definition.isThreadSingleton()) {
      globalFactory = new GlobalThreadSingletonFactory();
    } else if (definition.isFlyweight()) {
      globalFactory = new GlobalFlyweightFactory();
    }

    int namedLocalProductCount = definition.getNamedLocalProductCount();

    globalFactory.setLocalProductCount(namedLocalProductCount);

    /*
     * todo optimize this... so far all global factories have at least 1
     * named local product (the returned product)... but far from all global
     * factories actually reference it from life cycle phases.
     */
    if (definition.getNamedLocalProductCount() > 0) {
      instantiationFactory = new LocalProductProducerFactory(instantiationFactory, 0);
    }

    globalFactory.setLocalInstantiationFactory(instantiationFactory);

    if (definition.getPhaseFactories() != null && definition.getPhaseFactories().size() > 0) {
      for (String phase : definition.getPhaseFactories().keySet()) {
        List<FactoryDefinition> phaseFactories = definition.getPhaseFactories().get(phase);
        globalFactory.setPhase(phase, buildLocalFactories(container, phaseFactories));
      }
    }
    return globalFactory;
  }
  protected LocalFactory buildLocalFactoryRecursively(
      Container container, FactoryDefinition definition) {
    LocalFactory factory = null;

    try {
      List<LocalFactory> argumentFactories =
          buildLocalFactories(container, definition.getInstantiationArgFactories());

      // todo get this from castings in factory definition. Casting will
      // force a specific return type.
      Class<?>[] forcedArgumentTypes = getForcedArgumentTypes(argumentFactories, definition);

      if (definition.isConstructorFactory()) { // constructor factory
        factory =
            builder.createConstructorFactory(
                definition.getIdentifierOwnerClass(), argumentFactories, forcedArgumentTypes);
      } else if (definition.isStaticMethodFactory()) {
        // method invocation factory
        factory =
            builder.createStaticMethodFactory(
                definition.getIdentifier(),
                definition.getIdentifierOwnerClass(),
                argumentFactories,
                forcedArgumentTypes);
      } else if (definition.isInstanceMethodFactory()) {
        LocalFactory methodInvocationTargetFactory =
            buildLocalFactoryRecursively(container, definition.getIdentifierTargetFactory());
        factory =
            builder.createInstanceMethodFactory(
                definition.getIdentifier(),
                methodInvocationTargetFactory,
                argumentFactories,
                forcedArgumentTypes);
      } else if (definition.isInstanceFieldFactory()) {
        LocalFactory fieldTargetFactory =
            buildLocalFactoryRecursively(container, definition.getIdentifierTargetFactory());
        factory = builder.createFieldFactory(definition.getIdentifier(), fieldTargetFactory);
      } else if (definition.isStaticFieldFactory()) {
        factory =
            builder.createFieldFactory(
                definition.getIdentifier(), definition.getIdentifierOwnerClass());
      } else if (definition.isInstanceFieldAssignmentFactory()) {
        LocalFactory assignmentTargetFactory =
            buildLocalFactoryRecursively(container, definition.getIdentifierTargetFactory());
        factory =
            builder.createFieldAssignmentFactory(
                definition.getIdentifier(), assignmentTargetFactory, argumentFactories.get(0));
      } else if (definition.isStaticFieldAssignmentFactory()) {
        factory =
            builder.createFieldAssignmentFactory(
                definition.getIdentifier(),
                definition.getIdentifierOwnerClass(),
                argumentFactories.get(0));
      } else if (definition.isFactoryCallFactory()) { // existing factory
        // reference
        if (container.getFactory(definition.getIdentifier()) == null)
          throw new ParserException(
              "ScriptFactoryBuilder",
              "UNKNOWN_FACTORY",
              "Error in factory definition ["
                  + definition.getRoot().getName()
                  + "]: Unknown Factory: "
                  + definition.getIdentifier());
        factory =
            new InputAdaptingFactory(
                container.getFactory(definition.getIdentifier()), argumentFactories);
      } else if (definition.isFactoryFactory()) {
        factory = new FactoryFactory(container, definition.getIdentifier());
      } else if (definition.isCollectionFactory()) {
        factory = new CollectionFactory(argumentFactories);
      } else if (definition.isMapFactory()) {
        List<LocalFactory> keyFactories =
            buildLocalFactories(container, definition.getInstantiationArgKeyFactories());
        factory = new MapFactory(keyFactories, argumentFactories);

        if (definition.isLocalizedMap()) {
          ((MapFactory) factory).setFactoryMap(true);
          GlobalFactory<?> localeFactory = container.getFactory("locale");
          if (localeFactory == null) {
            new ParserException(
                "ScriptFactoryBuilder",
                "NO_LOCALE_FACTORY_FOUND",
                "Error in factory definition "
                    + definition.getRoot().getName()
                    + ": No 'locale' factory found. "
                    + "A 'locale' factory must be present in order to use localized resource factories");
          }
          factory = new LocalizedResourceFactory(factory, localeFactory);
        }
      } else if (definition.isValueFactory()) { // value factory
        if (isString(definition.getIdentifier()))
          factory =
              new ValueFactory(
                  definition.getIdentifier().substring(1, definition.getIdentifier().length() - 1));
        else if ("null".equals(definition.getIdentifier())) {
          factory = new ValueFactory(null);
        } else factory = new ValueFactory(definition.getIdentifier());
      } else if (definition.isInputParameterFactory()) { // input
        // consuming
        // factory
        factory = new InputConsumerFactory(Integer.parseInt(definition.getIdentifier()));
      } else if (definition.isLocalProductFactory()) {
        factory =
            new LocalProductConsumerFactory(
                definition.getLocalProductType(), definition.getLocalProductIndex());
      }

      // only local factories with a name (named local factories) can be
      // something else than "new instance"
      // factories.
      if (definition.isNamedLocalFactory()) {
        if (definition.isSingleton()) {
          factory = new LocalSingletonFactory(factory);
        } else if (definition.isThreadSingleton()) {
          factory = new LocalThreadSingletonFactory(factory);
        } else if (definition.isFlyweight()) {
          factory = new LocalFlyweightFactory(factory);
        }

        factory = new LocalProductProducerFactory(factory, definition.getLocalProductIndex());
        definition.setLocalProductType(definition.getName(), factory.getReturnType());
      }

      return factory;
    } catch (ContainerException e) {
      if (e.getCode().indexOf("ScriptFactoryBuilder") == -1) {
        e.addInfo(
            "ScriptFactoryBuilder",
            "ERROR_CREATING_FACTORY",
            "Error in factory definition " + definition.getRoot().getName());
      }
      throw e;
    }
  }