diff --git a/src/zabbix_java/src/com/zabbix/gateway/InternalItemChecker.java b/src/zabbix_java/src/com/zabbix/gateway/InternalItemChecker.java
index 4196fb8a72..b335571f3a 100644
--- a/src/zabbix_java/src/com/zabbix/gateway/InternalItemChecker.java
+++ b/src/zabbix_java/src/com/zabbix/gateway/InternalItemChecker.java
@@ -34,7 +34,47 @@ class InternalItemChecker extends ItemChecker
 	}
 
 	@Override
-	protected String getStringValue(String key) throws Exception
+	protected JSONArray getValues() throws ZabbixException
+	{
+		JSONArray values = new JSONArray();
+
+		for (String key : keys)
+			values.put(getJSONValue(key));
+
+		return values;
+	}
+
+
+	private JSONObject getJSONValue(String key)
+	{
+		JSONObject value = new JSONObject();
+
+		try
+		{
+			logger.debug("getting value for item '{}'", key);
+			String text = getStringValue(key);
+			logger.debug("received value '{}' for item '{}'", text, key);
+			value.put(JSON_TAG_VALUE, text);
+		}
+		catch (Exception e1)
+		{
+			try
+			{
+				logger.debug("caught exception for item '{}'", key, e1);
+				value.put(JSON_TAG_ERROR, ZabbixException.getRootCauseMessage(e1));
+			}
+			catch (JSONException e2)
+			{
+				Object[] logInfo = {JSON_TAG_ERROR, e1.getMessage(), ZabbixException.getRootCauseMessage(e2)};
+				logger.warn("cannot add JSON attribute '{}' with message '{}': {}", logInfo);
+				logger.debug("error caused by", e2);
+			}
+		}
+
+		return value;
+	}
+
+	private String getStringValue(String key) throws Exception
 	{
 		ZabbixItem item = new ZabbixItem(key);
 
diff --git a/src/zabbix_java/src/com/zabbix/gateway/ItemChecker.java b/src/zabbix_java/src/com/zabbix/gateway/ItemChecker.java
index 0d3c1ebc20..11fe375dff 100644
--- a/src/zabbix_java/src/com/zabbix/gateway/ItemChecker.java
+++ b/src/zabbix_java/src/com/zabbix/gateway/ItemChecker.java
@@ -67,49 +67,10 @@ abstract class ItemChecker
 		}
 	}
 
-	JSONArray getValues() throws ZabbixException
-	{
-		JSONArray values = new JSONArray();
-
-		for (String key : keys)
-			values.put(getJSONValue(key));
-
-		return values;
-	}
-
 	String getFirstKey()
 	{
 		return 0 == keys.size() ? null : keys.get(0);
 	}
 
-	protected final JSONObject getJSONValue(String key)
-	{
-		JSONObject value = new JSONObject();
-
-		try
-		{
-			logger.debug("getting value for item '{}'", key);
-			String text = getStringValue(key);
-			logger.debug("received value '{}' for item '{}'", text, key);
-			value.put(JSON_TAG_VALUE, text);
-		}
-		catch (Exception e1)
-		{
-			try
-			{
-				logger.debug("caught exception for item '{}'", key, e1);
-				value.put(JSON_TAG_ERROR, ZabbixException.getRootCauseMessage(e1));
-			}
-			catch (JSONException e2)
-			{
-				Object[] logInfo = {JSON_TAG_ERROR, e1.getMessage(), ZabbixException.getRootCauseMessage(e2)};
-				logger.warn("cannot add JSON attribute '{}' with message '{}': {}", logInfo);
-				logger.debug("error caused by", e2);
-			}
-		}
-
-		return value;
-	}
-
-	protected abstract String getStringValue(String key) throws Exception;
+	protected abstract JSONArray getValues() throws ZabbixException;
 }
diff --git a/src/zabbix_java/src/com/zabbix/gateway/JMXItemChecker.java b/src/zabbix_java/src/com/zabbix/gateway/JMXItemChecker.java
index 0651f1d755..449320e6a8 100644
--- a/src/zabbix_java/src/com/zabbix/gateway/JMXItemChecker.java
+++ b/src/zabbix_java/src/com/zabbix/gateway/JMXItemChecker.java
@@ -19,18 +19,24 @@
 
 package com.zabbix.gateway;
 
+import java.util.Set;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+import javax.lang.model.type.ErrorType;
 import javax.management.AttributeList;
 
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanServerConnection;
 import javax.management.ObjectName;
-import javax.management.MalformedObjectNameException;
 import javax.management.openmbean.CompositeData;
 import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.InvalidKeyException;
+import javax.management.MalformedObjectNameException;
 import javax.management.remote.JMXConnector;
 import javax.management.remote.JMXServiceURL;
 
@@ -53,6 +59,12 @@ class JMXItemChecker extends ItemChecker
 	static final int DISCOVERY_MODE_ATTRIBUTES = 0;
 	static final int DISCOVERY_MODE_BEANS = 1;
 
+	static final boolean SUCCESS = true;
+	static final boolean FAIL = false;
+
+	private static Map<String, Map<String, JSONObject>> dataObjectMap;
+	private AttributeList attributData;
+
 	JMXItemChecker(JSONObject request) throws ZabbixException
 	{
 		super(request);
@@ -84,13 +96,15 @@ class JMXItemChecker extends ItemChecker
 	}
 
 	@Override
-	JSONArray getValues() throws ZabbixException
+	protected JSONArray getValues() throws ZabbixException
 	{
 		JSONArray values = new JSONArray();
 
 		try
 		{
 			HashMap<String, String[]> env = null;
+			Set<String> processedKeys = new HashSet<String>();
+			dataObjectMap = new HashMap<String, Map<String, JSONObject>>();
 
 			if (null != username && null != password)
 			{
@@ -102,7 +116,66 @@ class JMXItemChecker extends ItemChecker
 			mbsc = jmxc.getMBeanServerConnection();
 
 			for (String key : keys)
-				values.put(getJSONValue(key));
+			{
+				ZabbixItem item = new ZabbixItem(key);
+
+				if (item.getKeyId().equals("jmx.discovery"))
+				{
+					getDiscoveryValue(key);
+				}
+				else if (item.getKeyId().equals("jmx"))
+				{
+					if (2 != item.getArgumentCount())
+					{
+						storeValue(key, null, "Incorrect item key, required key format: jmx[<object name>,<attribute name>].", FAIL);
+						continue;
+					}
+
+					String objectName = item.getArgument(1);
+
+					// keep track of keys that have been already processed
+					if (dataObjectMap.containsKey(objectName))
+						continue;
+
+					Map<String, JSONObject> attributeMap = new HashMap<String, JSONObject>();
+
+					for (String key2 : keys)
+					{
+						ZabbixItem item2 = new ZabbixItem(key2);
+
+						if (!item2.getKeyId().equals("jmx") || 2 != item2.getArgumentCount())
+							continue;
+
+						if (objectName.equals(item2.getArgument(1)))
+							attributeMap.put(item2.getArgument(2), null);
+					}
+
+					dataObjectMap.put(objectName, attributeMap);
+
+					attributData = new AttributeList();
+					getAttributeData(objectName);
+					processAttributeValues(objectName);
+				}
+				else
+					storeValue(key, null, "Cannot process key: ID '" + item.getKeyId() + "' is not supported.", FAIL);
+			}
+
+			for (String key : keys)
+			{
+				Map<String, JSONObject> attributeMap = new HashMap<String, JSONObject>();
+				ZabbixItem item = new ZabbixItem(key);
+
+				if (item.getKeyId().equals("jmx") && 2 == item.getArgumentCount())
+				{
+					attributeMap = dataObjectMap.get(item.getArgument(1));
+					values.put(attributeMap.get(item.getArgument(2)));
+				}
+				else
+				{
+					attributeMap = dataObjectMap.get(key);
+					values.put(attributeMap.get(JSON_TAG_DATA));
+				}
+			}
 		}
 		catch (SecurityException e1)
 		{
@@ -140,150 +213,254 @@ class JMXItemChecker extends ItemChecker
 		return values;
 	}
 
-	@Override
-	protected String getStringValue(String key) throws Exception
+	private void getAttributeData(String objectNameStr)
 	{
-		ZabbixItem item = new ZabbixItem(key);
+		String realAttributeName;
+		ObjectName objectName = null;
+		Map<String, JSONObject> attributes = new HashMap<String, JSONObject>();
+		ArrayList<String> attributeList = new ArrayList<String>();
 
-		if (item.getKeyId().equals("jmx"))
-		{
-			if (2 != item.getArgumentCount())
-				throw new ZabbixException("required key format: jmx[<object name>,<attribute name>]");
+		attributes = dataObjectMap.get(objectNameStr);
 
-			ObjectName objectName = new ObjectName(item.getArgument(1));
-			String attributeName = item.getArgument(2);
-			String realAttributeName;
-			String fieldNames = "";
+		// Attribute name and composite data field names are separated by dots. On the other hand the
+		// name may contain a dot too. In this case user needs to escape it with a backslash. Also the
+		// backslash symbols in the name must be escaped. So a real separator is unescaped dot and
+		// separatorIndex() is used to locate it.
 
-			// Attribute name and composite data field names are separated by dots. On the other hand the
-			// name may contain a dot too. In this case user needs to escape it with a backslash. Also the
-			// backslash symbols in the name must be escaped. So a real separator is unescaped dot and
-			// separatorIndex() is used to locate it.
-
-			int sep = HelperFunctionChest.separatorIndex(attributeName);
+		for (Map.Entry<String, JSONObject> attribute : attributes.entrySet())
+		{
+			realAttributeName = attribute.getKey();
+			int sep = HelperFunctionChest.separatorIndex(realAttributeName);
 
 			if (-1 != sep)
-			{
-				logger.trace("'{}' contains composite data", attributeName);
+				realAttributeName = realAttributeName.substring(0, sep);
 
-				realAttributeName = attributeName.substring(0, sep);
-				fieldNames = attributeName.substring(sep + 1);
-			}
-			else
-				realAttributeName = attributeName;
-
-			// unescape possible dots or backslashes that were escaped by user
-			realAttributeName = HelperFunctionChest.unescapeUserInput(realAttributeName);
+			// Create a list of atributes without composite data. Method getAttributes() retrievs all
+			// composite data values for an attribute.
+			attributeList.add(realAttributeName);
+		}
 
-			logger.trace("attributeName:'{}'", realAttributeName);
-			logger.trace("fieldNames:'{}'", fieldNames);
+		Iterator itr = attributeList.iterator();
 
-			try
-			{
-				return getPrimitiveAttributeValue(mbsc.getAttribute(objectName, realAttributeName), fieldNames);
-			}
-			catch (InstanceNotFoundException e)
+		try
+		{
+			objectName = new ObjectName(objectNameStr);
+			attributData = mbsc.getAttributes(objectName, attributeList.toArray(new String[0]));
+		}
+		catch (MalformedObjectNameException e)
+		{
+			while(itr.hasNext())
 			{
-				throw new ZabbixException("Object or attribute not found.");
+				storeValue(objectNameStr, itr.next().toString(), "Cannot get attribute data: the format of the object '"
+					+ objectNameStr + "' does not correspond to a valid ObjectName.", FAIL);
 			}
 		}
-		else if (item.getKeyId().equals("jmx.discovery"))
+		catch (Exception e1)
 		{
-			int argumentCount = item.getArgumentCount();
-
-			if (2 < argumentCount)
-				throw new ZabbixException("required key format: jmx.discovery[<discovery mode>,<object name>]");
+			while(itr.hasNext())
+			{
+				String attrName = itr.next().toString();
 
-			ObjectName filter;
+				try
+				{
+					Object attrValue = mbsc.getAttribute(objectName, attrName);
+					attributData.add(new javax.management.Attribute(attrName, attrValue));
+				}
+				catch (Exception e2)
+				{
+					storeValue(objectNameStr, attrName,
+						"Cannot get attribute data: invalid attribute registered on the MBean server.", FAIL);
 
-			try
-			{
-				filter = (2 == argumentCount) ? new ObjectName(item.getArgument(2)) : null;
-			}
-			catch (MalformedObjectNameException e)
-			{
-				throw new ZabbixException("invalid object name format: " + item.getArgument(2));
+				}
 			}
+		}
+	}
 
-			int mode = DISCOVERY_MODE_ATTRIBUTES;
-			if (0 != argumentCount)
-			{
-				String modeName = item.getArgument(1);
+	private void processAttributeValues(String objectNameStr)
+	{
+		if (attributData.isEmpty())
+			return;
 
-				if (modeName.equals("beans"))
-					mode = DISCOVERY_MODE_BEANS;
-				else if (!modeName.equals("attributes"))
-					throw new ZabbixException("invalid discovery mode: " + modeName);
-			}
+		String realAttributeName;
+		Map<String, JSONObject> attributes = new HashMap<String, JSONObject>();
 
-			JSONArray counters = new JSONArray();
+		attributes = dataObjectMap.get(objectNameStr);
 
-			for (ObjectName name : mbsc.queryNames(filter, null))
-			{
-				logger.trace("discovered object '{}'", name);
+		for (Map.Entry<String, JSONObject> attribute : attributes.entrySet())
+		{
+			String fieldName = "";
+			realAttributeName = attribute.getKey();
+			int sep = HelperFunctionChest.separatorIndex(attribute.getKey());
 
-				if (DISCOVERY_MODE_ATTRIBUTES == mode)
-					discoverAttributes(counters, name);
-				else
-					discoverBeans(counters, name);
+			if (-1 != sep)
+			{
+				realAttributeName = attribute.getKey().substring(0, sep);
+				fieldName = attribute.getKey().substring(sep + 1);
 			}
 
-			JSONObject mapping = new JSONObject();
-			mapping.put(ItemChecker.JSON_TAG_DATA, counters);
-			return mapping.toString();
+			for (javax.management.Attribute a : attributData.asList())
+			{
+				if (a.getName().equals(realAttributeName))
+				{
+					try
+					{
+						getPrimitiveAttributeValue(objectNameStr, attribute.getKey(), a.getValue(), fieldName);
+					}
+					catch (Exception e)
+					{
+						storeValue(objectNameStr, attribute.getKey(),
+							"Cannot process object or attribute: " + e.getMessage() + ".", FAIL);
+					}
+					break;
+				}
+			}
 		}
-		else
-			throw new ZabbixException("key ID '%s' is not supported", item.getKeyId());
 	}
 
-	private String getPrimitiveAttributeValue(Object dataObject, String fieldNames) throws Exception
+	private void getPrimitiveAttributeValue(String objectName, String atributeName, Object attributeValue, String fieldNames) throws Exception
 	{
-		logger.trace("drilling down with data object '{}' and field names '{}'", dataObject, fieldNames);
+		logger.trace("drilling down with data object '{}' and field names '{}'", attributeValue, fieldNames);
 
-		if (null == dataObject)
-			throw new ZabbixException("data object is null");
+		if (null == attributeValue)
+			throw new Exception("attribute object is empty");
 
 		if (fieldNames.equals(""))
 		{
 			try
 			{
-				if (isPrimitiveAttributeType(dataObject))
-					return dataObject.toString();
-				else
-					throw new NoSuchMethodException();
+				if (isPrimitiveAttributeType(attributeValue))
+				{
+					storeValue(objectName, atributeName, attributeValue.toString(), SUCCESS);
+					return;
+				}
 			}
 			catch (NoSuchMethodException e)
 			{
-				throw new ZabbixException("Data object type cannot be converted to string.");
+				throw new Exception("data object '" + attributeValue + "' type cannot be converted to string");
 			}
 		}
 
-		if (dataObject instanceof CompositeData)
+		if (attributeValue instanceof CompositeData)
 		{
-			logger.trace("'{}' contains composite data", dataObject);
+			logger.trace("'{}' contains composite data", attributeValue);
 
-			CompositeData comp = (CompositeData)dataObject;
+			Object compositeData;
+			CompositeData comp = (CompositeData)attributeValue;
 
-			String dataObjectName;
+			String attribute;
 			String newFieldNames = "";
 
 			int sep = HelperFunctionChest.separatorIndex(fieldNames);
 
 			if (-1 != sep)
 			{
-				dataObjectName = fieldNames.substring(0, sep);
+				attribute = fieldNames.substring(0, sep);
 				newFieldNames = fieldNames.substring(sep + 1);
 			}
 			else
-				dataObjectName = fieldNames;
+				attribute = fieldNames;
 
 			// unescape possible dots or backslashes that were escaped by user
-			dataObjectName = HelperFunctionChest.unescapeUserInput(dataObjectName);
+			attribute = HelperFunctionChest.unescapeUserInput(attribute);
+
+			try
+			{
+				compositeData = comp.get(attribute);
+				getPrimitiveAttributeValue(objectName, atributeName, compositeData, newFieldNames);
+			}
+			catch (InvalidKeyException e)
+			{
+				throw new Exception("'" + attribute + "' is not an existing item name for this CompositeData instance");
+			}
+		}
+		else
+			throw new Exception("unsupported attribute object type along the path: " + attributeValue.getClass());
+	}
+
+	private void getDiscoveryValue(String key) throws Exception
+	{
+		ZabbixItem item = new ZabbixItem(key);
+		int argumentCount = item.getArgumentCount();
+
+		if (2 < argumentCount)
+		{
+			storeValue(key, null, "Invalid key, required key format: jmx.discovery[<discovery mode>,<object name>].", FAIL);
+			return;
+		}
+
+		ObjectName filter;
+
+		try
+		{
+			filter = (2 == argumentCount) ? new ObjectName(item.getArgument(2)) : null;
+		}
+		catch (MalformedObjectNameException e)
+		{
+			storeValue(key, null, "Invalid object name format: " + item.getArgument(2) + ".", FAIL);
+			return;
+		}
 
-			return getPrimitiveAttributeValue(comp.get(dataObjectName), newFieldNames);
+		int mode = DISCOVERY_MODE_ATTRIBUTES;
+		if (0 != argumentCount)
+		{
+			String modeName = item.getArgument(1);
+
+			if (modeName.equals("beans"))
+			{
+				mode = DISCOVERY_MODE_BEANS;
+			}
+			else if (!modeName.equals("attributes"))
+			{
+				storeValue(key, null, "Invalid discovery mode: " + modeName + ".", FAIL);
+				return;
+			}
+		}
+
+		JSONArray counters = new JSONArray();
+
+		for (ObjectName name : mbsc.queryNames(filter, null))
+		{
+			logger.trace("discovered object '{}'", name);
+
+			if (DISCOVERY_MODE_ATTRIBUTES == mode)
+				discoverAttributes(counters, name);
+			else
+				discoverBeans(counters, name);
 		}
+
+		JSONObject mapping = new JSONObject();
+		mapping.put(JSON_TAG_DATA, counters);
+		storeValue(key, null, mapping.toString(), SUCCESS);
+	}
+
+	private void storeValue(String objectName, String atributeName, String valueStr, Boolean success)
+	{
+		JSONObject value = new JSONObject();
+		Map<String, JSONObject> attributeMap = new HashMap<String, JSONObject>();
+
+		if (null != atributeName)
+			attributeMap = dataObjectMap.get(objectName);
 		else
-			throw new ZabbixException("unsupported data object type along the path: %s", dataObject.getClass());
+			atributeName = JSON_TAG_DATA;
+
+		try
+		{
+			if (success)
+				value.put(JSON_TAG_VALUE, valueStr);
+			else
+				value.put(JSON_TAG_ERROR, valueStr);
+
+			attributeMap.put(atributeName, value);
+
+		}
+		catch (JSONException e)
+		{
+			Object[] logInfo = {JSON_TAG_ERROR, e.getMessage(), ZabbixException.getRootCauseMessage(e)};
+			logger.warn("cannot add JSON attribute '{}' with message '{}': {}", logInfo);
+			logger.debug("error caused by", e);
+		}
+
+		dataObjectMap.put(objectName, attributeMap);
 	}
 
 	private void discoverAttributes(JSONArray counters, ObjectName name) throws Exception
