gt: 					array = new boolean[adaptedCollection.size()];
context: /*
  Copyright (C) 2009 by Claas Wilke (claaswilke@gmx.net)
  
  This file is part of the Java Model Instance Plug-in of Dresden OCL2 for Eclipse.
  
  Dresden OCL2 for Eclipse 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 3 of the License, or (at your option)
  any later version.
  
  Dresden OCL2 for Eclipse 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 Dresden OCL2 for Eclipse. If not, see <http://www.gnu.org/licenses/>.
   */
  package org.dresdenocl.modelinstancetype.java.internal.modelinstance;
  
  import java.lang.reflect.Array;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.math.BigDecimal;
  import java.math.BigInteger;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashSet;
  import java.util.LinkedHashSet;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Set;
  import java.util.Stack;
  import java.util.TreeSet;
  import java.util.Vector;
  
  import org.apache.log4j.Logger;
  import org.eclipse.osgi.util.NLS;
  
  import org.dresdenocl.model.IModel;
  import org.dresdenocl.model.ModelAccessException;
  import org.dresdenocl.modelinstance.IModelInstance;
  import org.dresdenocl.modelinstance.base.AbstractModelInstance;
  import org.dresdenocl.modelinstancetype.exception.OperationAccessException;
  import org.dresdenocl.modelinstancetype.exception.OperationNotFoundException;
  import org.dresdenocl.modelinstancetype.exception.PropertyAccessException;
  import org.dresdenocl.modelinstancetype.exception.PropertyNotFoundException;
  import org.dresdenocl.modelinstancetype.exception.TypeNotFoundInModelException;
  import org.dresdenocl.modelinstancetype.java.JavaModelInstanceTypePlugin;
  import org.dresdenocl.modelinstancetype.java.internal.msg.JavaModelInstanceTypeMessages;
  import org.dresdenocl.modelinstancetype.java.internal.util.JavaModelInstanceTypeUtility;
  import org.dresdenocl.modelinstancetype.types.IModelInstanceBoolean;
  import org.dresdenocl.modelinstancetype.types.IModelInstanceCollection;
  import org.dresdenocl.modelinstancetype.types.IModelInstanceElement;
  import org.dresdenocl.modelinstancetype.types.IModelInstanceEnumerationLiteral;
  import org.dresdenocl.modelinstancetype.types.IModelInstanceInteger;
  import org.dresdenocl.modelinstancetype.types.IModelInstanceObject;
  import org.dresdenocl.modelinstancetype.types.IModelInstancePrimitiveType;
  import org.dresdenocl.modelinstancetype.types.IModelInstanceReal;
  import org.dresdenocl.modelinstancetype.types.IModelInstanceString;
  import org.dresdenocl.pivotmodel.EnumerationLiteral;
  import org.dresdenocl.pivotmodel.Operation;
  import org.dresdenocl.pivotmodel.Parameter;
  import org.dresdenocl.pivotmodel.Property;
  import org.dresdenocl.pivotmodel.Type;
  
  /**
   * <p>
   * Represents instances of {@link IModel}s represented by Java classes.
   * </p>
   * 
   * @author Claas Wilke
   */
  public class JavaModelInstance extends AbstractModelInstance {
  
  	/** The {@link Logger} for this class. */
  	private static final Logger LOGGER = JavaModelInstanceTypePlugin
  			.getLogger(JavaModelInstance.class);
  
  	/**
  	 * A counter used to generated default names for empty
  	 * {@link JavaModelInstance}s.
  	 */
  	private static int nameCounter = 0;
  
  	/**
  	 * The {@link ClassLoader}s of this {@link JavaModelInstance}. Required to
  	 * find {@link EnumerationLiteral}s, to get static {@link Property}s and to
  	 * invoke static {@link Operation}s.
  	 */
  	private Set<ClassLoader> myClassLoaders = new HashSet<ClassLoader>();
  
  	/**
  	 * <p>
  	 * Creates and initializes a new {@link JavaModelInstance}.
  	 * </p>
  	 * 
  	 * @param providerClass
  	 *            The provider class used to get all type instances of this
  	 *            model instance.
  	 * @param model
  	 *            The {@link IModel} of this {@link IModelInstance}.s
  	 * @throws TypeNotFoundInModelException
  	 *             Thrown if a model instance Object, cannot be adapted to a
  	 *             {@link Type} in the {@link IModel}.
  	 */
  	@SuppressWarnings("unchecked")
  	public JavaModelInstance(Class<?> providerClass, IModel model)
  			throws ModelAccessException, TypeNotFoundInModelException {
  
  		/* Eventually debug the entry of this method. */
  		if (LOGGER.isDebugEnabled()) {
  			String msg;
  
  			msg = "JavaModelInstance("; //$NON-NLS-1$
  			msg += "providerClass = " + providerClass; //$NON-NLS-1$
  			msg += ", model = " + model; //$NON-NLS-1$
  			msg += ")"; //$NON-NLS-1$
  
  			LOGGER.debug(msg);
  		}
  		// no else.
  
  		/* Initialize the instance. */
  		this.myModel = model;
  		this.myName = providerClass.getCanonicalName();
  		this.myClassLoaders.add(providerClass.getClassLoader());
  
  		this.myModelInstanceFactory = new JavaModelInstanceFactory(this.myModel);
  
  		/* Try to load the model instance objects. */
  		try {
  			Method providerMethod;
  			List<Object> providedObjects;
  
  			/* Get the provider method and its model objects. */
  			providerMethod = providerClass.getDeclaredMethod("getModelObjects",
  					new Class[0]);
  			providedObjects = (List<Object>) providerMethod.invoke(null,
  					new Object[0]);
  
  			/* Adapt all provided objects. */
  			this.addObjects(providedObjects);
  
  			/* Initialize the type Mapping of this model instance. */
  			this.initializeTypeMapping();
  		}
  
  		catch (NoSuchMethodException e) {
  			String msg;
  
  			msg = JavaModelInstanceTypeMessages.JavaModelInstance_ProviderMethodNotFound;
  			msg = NLS.bind(msg, providerClass);
  
  			LOGGER.error(msg);
  			throw new ModelAccessException(msg, e);
  		}
  
  		catch (IllegalArgumentException e) {
  			String msg;
  
  			msg = JavaModelInstanceTypeMessages.JavaModelInstance_ProviderMethodInvocationError;
  			msg = NLS.bind(msg, providerClass);
  
  			LOGGER.error(msg);
  			throw new ModelAccessException(msg, e);
  		}
  
  		catch (IllegalAccessException e) {
  			String msg;
  
  			msg = JavaModelInstanceTypeMessages.JavaModelInstance_ProviderMethodInvocationError;
  			msg = NLS.bind(msg, providerClass);
  
  			LOGGER.error(msg);
  			throw new ModelAccessException(msg, e);
  		}
  
  		catch (InvocationTargetException e) {
  			String msg;
  
  			msg = JavaModelInstanceTypeMessages.JavaModelInstance_ProviderMethodInvocationError;
  			msg = NLS.bind(msg, providerClass);
  
  			LOGGER.error(msg);
  			throw new ModelAccessException(msg, e);
  		}
  
  		catch (NoClassDefFoundError e) {
  			String msg;
  			msg = "Your model instance class "
  					+ providerClass
  					+ " could not be opened. Maybe it contains some unavailable imports or compile errors.";
  			LOGGER.error(msg);
  			throw new ModelAccessException(msg, e);
  		}
  
  		/* Eventually debug the exit of this method. */
  		if (LOGGER.isDebugEnabled()) {
  			String msg;
  
  			msg = "JavaModelInstance(Class<?>, IModel) - exit"; //$NON-NLS-1$
  
  			LOGGER.debug(msg);
  		}
  		// no else.
  	}
  
  	/**
  	 * <p>
  	 * Creates and initializes a new, empty {@link JavaModelInstance}.
  	 * </p>
  	 * 
  	 * <p>
  	 * <strong>Please note that an empty {@link JavaModelInstance} cannot be
  	 * used to find static {@link Property}s and static {@link Operation}s until
  	 * at least one {@link Object} has been added whose {@link ClassLoader}
  	 * knows the {@link Class} of the static {@link Property} or
  	 * {@link Operation}!</strong>
  	 * </p>
  	 * 
  	 * @param model
  	 *            The {@link IModel} of this {@link IModelInstance}.s
  	 */
  	public JavaModelInstance(IModel model) {
  
  		/* Eventually debug the entry of this method. */
  		if (LOGGER.isDebugEnabled()) {
  			String msg;
  
  			msg = "JavaModelInstance("; //$NON-NLS-1$
  			msg += "model = " + model; //$NON-NLS-1$
  			msg += ")"; //$NON-NLS-1$
  
  			LOGGER.debug(msg);
  		}
  		// no else.
  
  		/* Initialize the instance. */
  		this.myModel = model;
  
  		this.myName = this.getClass().getSimpleName() + nameCounter;
  		nameCounter++;
  
  		this.myModelInstanceFactory = new JavaModelInstanceFactory(this.myModel);
  
  		/* Eventually debug the exit of this method. */
  		if (LOGGER.isDebugEnabled()) {
  			String msg;
  
  			msg = "JavaModelInstance(IModel) - exit"; //$NON-NLS-1$
  
  			LOGGER.debug(msg);
  		}
  		// no else.
  	}
  
  	/**
  	 * <p>
  	 * Returns or creates the element that is adapted by a given
  	 * {@link IModelInstanceElement}. E.g., if the given
  	 * {@link IModelInstanceElement} is an {@link IModelInstanceObject}, the
  	 * adapted {@link Object} is simply returned. For
  	 * {@link IModelInstancePrimitiveType}, a newly created primitive is
  	 * returned.
  	 * </p>
  	 * 
  	 * @param modelInstanceElement
  	 *            The {@link IModelInstanceElement} those adapted {@link Object}
  	 *            shall be returned or created.
  	 * @param typeClass
  	 *            The {@link Class} the recreated element should be an instance
  	 *            of. This could be required for
  	 *            {@link IModelInstancePrimitiveType}s or for
  	 *            {@link IModelInstanceCollection}s.
  	 * @param classLoaders
  	 *            A {@link Set} of {@link ClassLoader}s that can probably be
  	 *            used to load required {@link Class}es for the adaptation.
  	 * @return The created or adapted value ({@link Object}).
  	 */
  	@SuppressWarnings("unchecked")
  	protected static Object createAdaptedElement(
  			IModelInstanceElement modelInstanceElement, Class<?> typeClass,
  			Set<ClassLoader> classLoaders) {
  
  		Object result;
  
  		/* Check for null values. */
  		if (modelInstanceElement == null) {
  			result = null;
  		}
  
  		/* Else check if the given element is a primitive type. */
  		else if (modelInstanceElement instanceof IModelInstancePrimitiveType) {
  
  			/* Probably recreate a boolean value. */
  			if (modelInstanceElement instanceof IModelInstanceBoolean) {
  
  				result = ((IModelInstanceBoolean) modelInstanceElement)
  						.getBoolean();
  			}
  
  			/* Else probably recreate an integer value. */
  			else if (modelInstanceElement instanceof IModelInstanceInteger) {
  
  				result = createAdaptedIntegerValue(
  						(IModelInstanceInteger) modelInstanceElement, typeClass);
  			}
  
  			/* Else probably recreate a real value. */
  			else if (modelInstanceElement instanceof IModelInstanceReal) {
  
  				result = createAdaptedRealValue(
  						(IModelInstanceReal) modelInstanceElement, typeClass);
  			}
  
  			/* Else probably recreate an String value. */
  			else if (modelInstanceElement instanceof IModelInstanceString) {
  
  				result = createAdaptedStringValue(
  						(IModelInstanceString) modelInstanceElement, typeClass);
  			}
  
  			else {
  				/* Other primitive types are not supported. Return null. */
  				result = null;
  			}
  		}
  
  		/* Else check if the given element is an enumeration literal. */
  		else if (modelInstanceElement instanceof IModelInstanceEnumerationLiteral) {
  
  			result = createAdaptedEnumerationLiteral(
  					(IModelInstanceEnumerationLiteral) modelInstanceElement,
  					typeClass, classLoaders);
  		}
  
  		/* Else check if the given element is a collection. */
  		else if (modelInstanceElement instanceof IModelInstanceCollection) {
  
  			/* Eventually adapt to an array. */
  			if (typeClass.isArray()) {
  				result = createAdaptedArray(modelInstanceElement, typeClass,
  						classLoaders);
  			}
  
  			/* Else use the collection. */
  			else if (Collection.class.isAssignableFrom(typeClass)) {
  				result = createAdaptedCollection(
  						(IModelInstanceCollection<IModelInstanceElement>) modelInstanceElement,
  						typeClass, classLoaders);
  			}
  
  			/* Else throw an exception. */
  			else {
  				String msg;
  				msg = JavaModelInstanceTypeMessages.JavaModelInstance_CannotRecreateCollection;
  
  				throw new IllegalArgumentException(msg);
  			}
  		}
  
  		/* Else check if the given element is an adapted object. */
  		else if (modelInstanceElement instanceof IModelInstanceObject) {
  
  			result = ((IModelInstanceObject) modelInstanceElement).getObject();
  		}
  
  		/* Other types are not known. */
  		else {
  			result = null;
  		}
  
  		return result;
  	}
  
  	/**
  	 * <p>
  	 * A helper method the converts a given {@link IModelInstanceElement} into
  	 * an Array value of a given {@link Class}.
  	 * </p>
  	 * 
  	 * @param modelInstanceElement
  	 *            The {@link IModelInstanceElement} that shall be converted.
  	 * @param type
  	 *            The {@link Class} to that the given
  	 *            {@link IModelInstanceElement} shall be converted.
  	 * @param classLoaders
  	 *            A {@link Set} of {@link ClassLoader}s that can probably be
  	 *            used to load required {@link Class}es for the adaptation.
  	 * @return The converted {@link Object}.
  	 */
  	@SuppressWarnings("unchecked")
  	private static Object createAdaptedArray(
  			IModelInstanceElement modelInstanceElement, Class<?> type,
  			Set<ClassLoader> classLoaders) {
  
  		Object result;
  
  		if (modelInstanceElement instanceof IModelInstanceCollection) {
  
  			IModelInstanceCollection<IModelInstanceElement> modelInstanceCollection;
  			Collection<IModelInstanceElement> adaptedCollection;
  
  			Class<?> componentType;
  			int index;
  
  			componentType = type.getComponentType();
  
  			modelInstanceCollection = (IModelInstanceCollection<IModelInstanceElement>) modelInstanceElement;
  			adaptedCollection = modelInstanceCollection.getCollection();
  
  			if (componentType.isPrimitive()) {
  
  				/* Probably create an array of boolean. */
  				if (boolean.class.isAssignableFrom(componentType)) {
  
  					boolean[] array;
  