* @param zclClusterDescriptor
	 * @throws Exception
	 */

	private void generateClusterAssets(JCodeModel jModel, JPackage jPackage, ZclClusterDescriptor zclClusterDescriptor,
			boolean isServer) throws Exception {
		JDefinedClass jClusterConnectionClass = null;
		
		if (generateConnectionClass)
			jClusterConnectionClass = jPackage._class(getClusterImplementationName(zclClusterDescriptor, isServer));

		JDefinedClass jClusterInterface = jPackage._interface(getClusterInterfaceName(zclClusterDescriptor, isServer));

		if (ifExtendsIServiceCluster)
			jClusterInterface._extends(IServiceCluster.class);

		if (jClusterConnectionClass != null)
			jClusterConnectionClass._extends(IServiceCluster.class);

		if (addJavadoc) {
			if (jClusterConnectionClass != null)
				jClusterConnectionClass.javadoc().add(copyrightClass);

			jClusterInterface.javadoc().add(copyrightInterface);
		}

		//
		// generates the interface part
		//

		// generates the interface constants
		String clusterFullname = getClusterFullname(zclClusterDescriptor);

		if (addClusterName) {
			JFieldVar jFieldClusterName = jClusterInterface.field(JMod.STATIC | JMod.FINAL, String.class, "NAME");

			if (isServer) {
				// TODO: read the name from other variables
				jFieldClusterName.init(JExpr.lit(clusterFullname + "Server"));
			} else {
				// TODO: read the name from other variables
				jFieldClusterName.init(JExpr.lit(clusterFullname + "Client"));
			}
		}

		// generates attribute getters and setters
		Vector zclAttributeDescriptors = null;
		Vector zclCommandsDescriptors = null;
		if (isServer) {
			zclAttributeDescriptors = zclClusterDescriptor.getZclServerAttributesDescriptors();
			zclCommandsDescriptors = zclClusterDescriptor.getZclServerCommandsDescriptors();
		} else {
			zclAttributeDescriptors = zclClusterDescriptor.getZclClientAttributesDescriptors();
			zclCommandsDescriptors = zclClusterDescriptor.getZclClientCommandsDescriptors();
		}

		JDefinedClass jClusterProxyClass = null;
		JFieldVar jFieldProxy = null;

		if (generateProxyClasses) {
			int commands = 0;
			for (int i = 0; i < zclCommandsDescriptors.size(); i++) {
				ZclCommandDescriptor zclCommandDescriptor = (ZclCommandDescriptor) zclCommandsDescriptors.get(i);
				if (zclCommandDescriptor.isResponse())
					continue;
				commands++;
			}

			if ((zclAttributeDescriptors.size() + commands) > 0) {
				// The proxy class is generated only if the cluster has at least
				// one command or attribute.
				jClusterProxyClass = jPackage._class(getClusterProxyName(zclClusterDescriptor, isServer));
				jClusterProxyClass._extends(ServiceCluster.class);
				jClusterProxyClass._implements(jClusterInterface);
			}
		}

		// generates implementation of the proxy class
		if (jClusterProxyClass != null) {

			jFieldProxy = jClusterProxyClass.field(JMod.PRIVATE, jClusterInterface, "o");
			jFieldProxy.init(JExpr._null());

			JMethod constructor = jClusterProxyClass.constructor(JMod.PUBLIC);
			JVar o = constructor.param(jClusterInterface, "o");
			constructor.body().invoke("super");
			constructor.body()._if(o.eq(JExpr._null()))._then()
					._throw(JExpr._new(jModel.ref(ApplianceValidationException.class)).arg("Invalid cluster implementation"));
			constructor.body().assign(JExpr._this().ref(jFieldProxy), o);
			constructor._throws(ApplianceException.class);
		}

		// generates the attributes and command names as constants
		for (int i = 0; i < zclAttributeDescriptors.size(); i++) {
			ZclAttributeDescr zclAttributeDescriptor = (ZclAttributeDescr) zclAttributeDescriptors.get(i);
			String attributeName = zclAttributeDescriptor.getName();

			JFieldVar jField = jClusterInterface.field(JMod.STATIC | JMod.FINAL, String.class,
					getAttributeNameConstant(attributeName));
			jField.init(JExpr.lit(attributeName));
		}

		for (int i = 0; i < zclCommandsDescriptors.size(); i++) {
			ZclCommandDescriptor zclCommandDescriptor = (ZclCommandDescriptor) zclCommandsDescriptors.get(i);
			if (zclCommandDescriptor.isResponse())
				continue;

			String commandName = zclCommandDescriptor.getName();
			JFieldVar jField = jClusterInterface.field(JMod.STATIC | JMod.FINAL, String.class, getCommandNameConstant(commandName));
			jField.init(JExpr.lit(commandName));
		}

		for (int i = 0; i < zclAttributeDescriptors.size(); i++) {
			ZclAttributeDescr zclAttributeDescriptor = (ZclAttributeDescr) zclAttributeDescriptors.get(i);
			generateAttributeGetterSignature(jModel, jClusterInterface, zclAttributeDescriptor, true);

			if (jClusterProxyClass != null) {
				// delegation method implementation in the Proxy class
				JMethod jProxyGetterMethod = generateAttributeGetterSignature(jModel, jClusterProxyClass, zclAttributeDescriptor,
						true);

				JInvocation a = jFieldProxy.invoke(jProxyGetterMethod.name());
				JVar[] params = jProxyGetterMethod.listParams();

				for (int j = 0; j < params.length; j++) {
					a.arg(params[j]);
				}

				jProxyGetterMethod.body()._return(a);
			}

			if (zclAttributeDescriptor.getAccess() == ZclAttributeDescr.ACCESS_RW) {
				generateAttributeSetterSignature(jModel, jClusterInterface, zclAttributeDescriptor, true);

				if (jClusterProxyClass != null) {
					JMethod jProxySetterMethod = generateAttributeSetterSignature(jModel, jClusterProxyClass,
							zclAttributeDescriptor, true);

					JInvocation a = jFieldProxy.invoke(jProxySetterMethod.name());
					JVar[] params = jProxySetterMethod.listParams();

					for (int j = 0; j < params.length; j++) {
						a.arg(params[j]);
					}
				}
			}
		}

		// generates command signatures
		for (int i = 0; i < zclCommandsDescriptors.size(); i++) {
			ZclCommandDescriptor zclCommandDescriptor = (ZclCommandDescriptor) zclCommandsDescriptors.get(i);
			generateCommandSignature(jClusterInterface, zclCommandDescriptor, true);

			if (jClusterProxyClass != null) {
				JMethod jProxyCommandMethod = generateCommandSignature(jClusterProxyClass, zclCommandDescriptor, true);
				if (jProxyCommandMethod == null)
					continue;

				JInvocation a = jFieldProxy.invoke(jProxyCommandMethod.name());
				JVar[] params = jProxyCommandMethod.listParams();

				for (int j = 0; j < params.length; j++) {
					a.arg(params[j]);
				}

				System.out.println(jProxyCommandMethod.type().name());

				if (jProxyCommandMethod.type() == jModel.VOID)
					jProxyCommandMethod.body().add(a);
				else
					jProxyCommandMethod.body()._return(a);
			}
		}

		//
		// generates the implementation part
		//

		// generates constructor
		if (jClusterConnectionClass != null) {
			JMethod constructor = jClusterConnectionClass.constructor(JMod.PUBLIC);
			// constructor.param(IManagedApplianceConnection.class,
			// "applianceConnection");
			constructor.body().directStatement(
					"super(applianceConnection, " + getClusterInterfaceName(zclClusterDescriptor, true) + ".NAME);");

			for (int i = 0; i < zclCommandsDescriptors.size(); i++) {
				ZclCommandDescriptor zclCommandDescriptor = (ZclCommandDescriptor) zclCommandsDescriptors.get(i);
				generateCommandImplementation(jClusterConnectionClass, jClusterInterface, zclCommandDescriptor);
			}

			for (int i = 0; i < zclAttributeDescriptors.size(); i++) {
				ZclAttributeDescr zclAttributeDescriptor = (ZclAttributeDescr) zclAttributeDescriptors.get(i);

				generateAttributeGetterImplementation(jModel, jClusterConnectionClass, jClusterInterface, zclAttributeDescriptor);

				if (zclAttributeDescriptor.getAccess() == ZclAttributeDescr.ACCESS_RW)
					generateAttributeSetterImplementation(jModel, jClusterConnectionClass, jClusterInterface,
							zclAttributeDescriptor);
			}
		}
	}