container/profiles/src/main/java/org/mobicents/slee/container/deployment/profile/jpa/ConcreteProfileEntityGenerator.java
private Class<?> generateProfileAttributeArrayValueClass(CtClass concreteProfileEntityClass, String profileAttributeName, boolean unique) {
	
	  CtClass concreteArrayValueClass = null;
	  
	  try {
		  
		  // define the concrete profile attribute array value class name
		  String concreteArrayValueClassName = profileComponent.getProfileCmpInterfaceClass().getName() + "PEAAV_"+ClassGeneratorUtils.capitalize(profileAttributeName);   

		  // create javassist class
		  concreteArrayValueClass = ClassGeneratorUtils.createClass(concreteArrayValueClassName, new String[]{Serializable.class.getName()});

		  // set inheritance
		  ClassGeneratorUtils.createInheritanceLink(concreteArrayValueClass, ProfileEntityArrayAttributeValue.class.getName());

		  // annotate class with @Entity
		  ClassGeneratorUtils.addAnnotation( Entity.class.getName(), new LinkedHashMap<String, Object>(), concreteArrayValueClass );    

		  // generate a random table name
		  addTableAnnotationToPEAAV("SLEE_PEAAV_"+profileComponent.getProfileCmpInterfaceClass().getSimpleName() + "_" + Math.abs((long)profileComponent.getComponentID().hashCode()) + profileAttributeName,unique,concreteArrayValueClass);  
		  		  
		  // override @id
		  String getIdNameMethodSrc = "public long getId() { return super.getId(); }";
		  CtMethod getIdNameMethod = CtNewMethod.make(getIdNameMethodSrc, concreteArrayValueClass);
		  ClassGeneratorUtils.addAnnotation( Id.class.getName(), new LinkedHashMap<String, Object>(), getIdNameMethod);
		  ClassGeneratorUtils.addAnnotation( GeneratedValue.class.getName(), new LinkedHashMap<String, Object>(), getIdNameMethod);
		  concreteArrayValueClass.addMethod(getIdNameMethod);
		  
		  // override getter methods
		  String getSerializableMethodSrc = "public "+Serializable.class.getName()+" getSerializable() { return super.getSerializable(); }";
		  CtMethod getSerializableMethod = CtNewMethod.make(getSerializableMethodSrc, concreteArrayValueClass);
		  LinkedHashMap<String,Object> map = new LinkedHashMap<String, Object>();
		  map.put("name", "serializable");
		  map.put("length", 512);
		  //if (unique)map.put("unique", true);
		  ClassGeneratorUtils.addAnnotation(Column.class.getName(), map, getSerializableMethod);
		  concreteArrayValueClass.addMethod(getSerializableMethod);
		  String getStringMethodSrc = "public String getString() { return super.getString(); }";
		  CtMethod getStringMethod = CtNewMethod.make(getStringMethodSrc, concreteArrayValueClass);
		  map = new LinkedHashMap<String, Object>();
		  map.put("name", "string");
		  //if (unique)map.put("unique", true);
		  ClassGeneratorUtils.addAnnotation(Column.class.getName(), map, getStringMethod);
		  concreteArrayValueClass.addMethod(getStringMethod);

		  // FIXME add join columns here or in profile entity class to make
		  // the relation without a join table, atm if this is changed, the
		  // inserts on this table go with profile and table name as null %)
		  // THE PROFILENTITY FIELD IN AAV CLASS IS REQUIRED FOR THE RELATION WITH PROFILE ENTITY CLASS WITHOUT A JOIN TABLE
		  // add join column regarding the relation from array attr value to profile entity
		  CtField ctField = ClassGeneratorUtils.addField(concreteProfileEntityClass, "owner", concreteArrayValueClass);
		  ClassGeneratorUtils.generateSetter(ctField,null);
		  CtMethod getter = ClassGeneratorUtils.generateGetter(ctField,null);
		  //ClassGeneratorUtils.addAnnotation(ManyToOne.class.getName(), new LinkedHashMap<String, Object>(), getter);
		  // ----
		  ConstPool cp = getter.getMethodInfo().getConstPool();
		  AnnotationsAttribute attr = (AnnotationsAttribute) getter.getMethodInfo().getAttribute(AnnotationsAttribute.visibleTag);
		  if (attr == null) {
			  attr = new AnnotationsAttribute(cp,AnnotationsAttribute.visibleTag);
		  }
		  
		  Annotation manyToOne = new Annotation(ManyToOne.class.getName(), cp);
		  manyToOne.addMemberValue("optional", new BooleanMemberValue(false,cp));
		  attr.addAnnotation(manyToOne);
		  
		  Annotation joinColumns = new Annotation(JoinColumns.class.getName(), cp);
		  Annotation joinColumn1 = new Annotation(JoinColumn.class.getName(), cp);
		  joinColumn1.addMemberValue("name", new StringMemberValue("owner_tableName", cp));
		  joinColumn1.addMemberValue("referencedColumnName", new StringMemberValue("tableName", cp));
		  Annotation joinColumn2 = new Annotation(JoinColumn.class.getName(), cp);
		  joinColumn2.addMemberValue("name", new StringMemberValue("owner_profileName", cp));
		  joinColumn2.addMemberValue("referencedColumnName", new StringMemberValue("profileName", cp));
		  ArrayMemberValue joinColumnsMemberValue = new ArrayMemberValue(cp);
    	  joinColumnsMemberValue.setValue(new MemberValue[] { new AnnotationMemberValue(joinColumn1,cp), new AnnotationMemberValue(joinColumn2,cp)});
    	  joinColumns.addMemberValue("value", joinColumnsMemberValue);
    	  attr.addAnnotation(joinColumns);
    	  
    	  getter.getMethodInfo().addAttribute(attr);
		  
    	  // generate concrete setProfileEntity method
    	  String setProfileEntityMethodSrc = "public void setProfileEntity("+ProfileEntity.class.getName()+" profileEntity){ setOwner(("+concreteProfileEntityClass.getName()+")profileEntity); }";
    	  CtMethod setProfileEntityMethod = CtMethod.make(setProfileEntityMethodSrc, concreteArrayValueClass);
    	  concreteArrayValueClass.addMethod(setProfileEntityMethod);
    	      	  
		  // write and load the attr array value class
		  String deployDir = profileComponent.getDeploymentDir().getAbsolutePath();
		  if (logger.isDebugEnabled()) {
			  logger.debug( "Writing PROFILE ATTR ARRAY VALUE CONCRETE CLASS ( "+concreteArrayValueClass.getName()+" ) to: " + deployDir );
		  }
		   concreteArrayValueClass.writeFile( deployDir );
		  
		  return Thread.currentThread().getContextClassLoader().loadClass(concreteArrayValueClass.getName());      
	  }
	  catch (Throwable e) {
		  throw new SLEEException(e.getMessage(),e);
	  }
	  finally {
		  if (concreteArrayValueClass != null) {
			  concreteArrayValueClass.defrost();
		  }
	  }
  }
private Class<?> generateProfileAttributeArrayValueClass(CtClass concreteProfileEntityClass, String profileAttributeName, boolean unique) {
	
	  CtClass concreteArrayValueClass = null;
	  
	  try {
		  
		  // define the concrete profile attribute array value class name
		  String concreteArrayValueClassName = profileComponent.getProfileCmpInterfaceClass().getName() + "PEAAV_"+ClassGeneratorUtils.capitalize(profileAttributeName);   

		  // create javassist class
		  concreteArrayValueClass = ClassGeneratorUtils.createClass(concreteArrayValueClassName, new String[]{Serializable.class.getName()});

		  // set inheritance
		  ClassGeneratorUtils.createInheritanceLink(concreteArrayValueClass, ProfileEntityArrayAttributeValue.class.getName());

		  // annotate class with @Entity
		  ClassGeneratorUtils.addAnnotation( Entity.class.getName(), new LinkedHashMap<String, Object>(), concreteArrayValueClass );    

		  // generate a random table name
		  addTableAnnotationToPEAAV("SLEE_PEAAV_"+profileComponent.getProfileCmpInterfaceClass().getSimpleName() + "_" + Math.abs((long)profileComponent.getComponentID().hashCode()) + profileAttributeName,unique,concreteArrayValueClass);  
		  		  
		  // override @id
		  String getIdNameMethodSrc = "public long getId() { return super.getId(); }";
		  CtMethod getIdNameMethod = CtNewMethod.make(getIdNameMethodSrc, concreteArrayValueClass);
		  ClassGeneratorUtils.addAnnotation( Id.class.getName(), new LinkedHashMap<String, Object>(), getIdNameMethod);
		  ClassGeneratorUtils.addAnnotation( GeneratedValue.class.getName(), new LinkedHashMap<String, Object>(), getIdNameMethod);
		  concreteArrayValueClass.addMethod(getIdNameMethod);
		  
		  // override getter methods
		  String getSerializableMethodSrc = "public "+Serializable.class.getName()+" getSerializable() { return super.getSerializable(); }";
		  CtMethod getSerializableMethod = CtNewMethod.make(getSerializableMethodSrc, concreteArrayValueClass);
		  LinkedHashMap<String,Object> map = new LinkedHashMap<String, Object>();
		  map.put("name", "serializable");
		  map.put("length", 512);
		  //if (unique)map.put("unique", true);
		  ClassGeneratorUtils.addAnnotation(Column.class.getName(), map, getSerializableMethod);
		  concreteArrayValueClass.addMethod(getSerializableMethod);
		  String getStringMethodSrc = "public String getString() { return super.getString(); }";
		  CtMethod getStringMethod = CtNewMethod.make(getStringMethodSrc, concreteArrayValueClass);
		  map = new LinkedHashMap<String, Object>();
		  map.put("name", "string");
		  //if (unique)map.put("unique", true);
		  ClassGeneratorUtils.addAnnotation(Column.class.getName(), map, getStringMethod);
		  concreteArrayValueClass.addMethod(getStringMethod);

		  // FIXME add join columns here or in profile entity class to make
		  // the relation without a join table, atm if this is changed, the
		  // inserts on this table go with profile and table name as null %)
		  // THE PROFILENTITY FIELD IN AAV CLASS IS REQUIRED FOR THE RELATION WITH PROFILE ENTITY CLASS WITHOUT A JOIN TABLE
		  // add join column regarding the relation from array attr value to profile entity
		  CtField ctField = ClassGeneratorUtils.addField(concreteProfileEntityClass, "owner", concreteArrayValueClass);
		  ClassGeneratorUtils.generateSetter(ctField,null);
		  CtMethod getter = ClassGeneratorUtils.generateGetter(ctField,null);
		  //ClassGeneratorUtils.addAnnotation(ManyToOne.class.getName(), new LinkedHashMap<String, Object>(), getter);
		  // ----
		  ConstPool cp = getter.getMethodInfo().getConstPool();
		  AnnotationsAttribute attr = (AnnotationsAttribute) getter.getMethodInfo().getAttribute(AnnotationsAttribute.visibleTag);
		  if (attr == null) {
			  attr = new AnnotationsAttribute(cp,AnnotationsAttribute.visibleTag);
		  }
		  
		  Annotation manyToOne = new Annotation(ManyToOne.class.getName(), cp);
		  manyToOne.addMemberValue("optional", new BooleanMemberValue(false,cp));
		  attr.addAnnotation(manyToOne);
		  
		  Annotation joinColumns = new Annotation(JoinColumns.class.getName(), cp);
		  Annotation joinColumn1 = new Annotation(JoinColumn.class.getName(), cp);
		  joinColumn1.addMemberValue("name", new StringMemberValue("owner_tableName", cp));
		  joinColumn1.addMemberValue("referencedColumnName", new StringMemberValue("tableName", cp));
		  Annotation joinColumn2 = new Annotation(JoinColumn.class.getName(), cp);
		  joinColumn2.addMemberValue("name", new StringMemberValue("owner_profileName", cp));
		  joinColumn2.addMemberValue("referencedColumnName", new StringMemberValue("profileName", cp));
		  ArrayMemberValue joinColumnsMemberValue = new ArrayMemberValue(cp);
    	  joinColumnsMemberValue.setValue(new MemberValue[] { new AnnotationMemberValue(joinColumn1,cp), new AnnotationMemberValue(joinColumn2,cp)});
    	  joinColumns.addMemberValue("value", joinColumnsMemberValue);
    	  attr.addAnnotation(joinColumns);
    	  
    	  getter.getMethodInfo().addAttribute(attr);
		  
    	  // generate concrete setProfileEntity method
    	  String setProfileEntityMethodSrc = "public void setProfileEntity("+ProfileEntity.class.getName()+" profileEntity){ setOwner(("+concreteProfileEntityClass.getName()+")profileEntity); }";
    	  CtMethod setProfileEntityMethod = CtMethod.make(setProfileEntityMethodSrc, concreteArrayValueClass);
    	  concreteArrayValueClass.addMethod(setProfileEntityMethod);
    	      	  
		  // write and load the attr array value class
		  String deployDir = profileComponent.getDeploymentDir().getAbsolutePath();
		  if (logger.isDebugEnabled()) {
			  logger.debug( "Writing PROFILE ATTR ARRAY VALUE CONCRETE CLASS ( "+concreteArrayValueClass.getName()+" ) to: " + deployDir );
		  }
		   concreteArrayValueClass.writeFile( deployDir );
		  
		  return Thread.currentThread().getContextClassLoader().loadClass(concreteArrayValueClass.getName());      
	  }
	  catch (Throwable e) {
		  throw new SLEEException(e.getMessage(),e);
	  }
	  finally {
		  if (concreteArrayValueClass != null) {
			  concreteArrayValueClass.defrost();
		  }
	  }
  }
Generates a class that extends {@link ProfileEntityArrayAttributeValue} for a specific entity attribute of array type value
@param concreteProfileEntityClass
@param profileAttributeName
@return