All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.datakernel.jmx.AttributeNodeForList Maven / Gradle / Ivy

Go to download

An intelligent way of booting complex applications and services according to their dependencies

There is a newer version: 3.1.0
Show newest version
/*
 * Copyright (C) 2015 SoftIndex LLC.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.datakernel.jmx;

import javax.management.openmbean.*;
import java.lang.reflect.Array;
import java.util.*;

import static io.datakernel.util.CollectionUtils.first;
import static io.datakernel.util.Preconditions.checkArgument;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;

final class AttributeNodeForList extends AttributeNodeForLeafAbstract {
	private final AttributeNode subNode;
	private final ArrayType arrayType;
	private final boolean isListOfJmxRefreshables;

	public AttributeNodeForList(String name, String description, boolean visible, ValueFetcher fetcher, AttributeNode subNode,
	                            boolean isListOfJmxRefreshables) {
		super(name, description, fetcher, visible);
		checkArgument(!name.isEmpty(), "List attribute cannot have empty name");
		this.subNode = subNode;
		this.arrayType = createArrayType(subNode, name);
		this.isListOfJmxRefreshables = isListOfJmxRefreshables;
	}

	private static ArrayType createArrayType(AttributeNode subNode, String name) {
		String nodeName = "Attribute name = " + name;

		Set visibleAttrs = subNode.getVisibleAttributes();
		Map> attrTypes = subNode.getOpenTypes();

		if (visibleAttrs.size() == 0) {
			throw new IllegalArgumentException("Arrays must have at least one visible attribute. " + nodeName);
		}

		try {
			OpenType elementType;
			if (visibleAttrs.size() == 1) {
				String attr = first(visibleAttrs);
				OpenType openType = attrTypes.get(attr);

				// TODO(vmykhalko): check this case
				if (openType instanceof ArrayType) {
					throw new IllegalArgumentException("Multidimensional arrays are note supported in JMX. " + nodeName);
				}

				elementType = openType;
			} else {
				List itemNames = new ArrayList<>();
				List> itemTypes = new ArrayList<>();
				for (String visibleAttr : visibleAttrs) {
					OpenType visibleAttrType = attrTypes.get(visibleAttr);
					itemNames.add(visibleAttr);
					itemTypes.add(visibleAttrType);
				}

				String[] itemNamesArr = itemNames.toArray(new String[itemNames.size()]);
				OpenType[] itemTypesArr = itemTypes.toArray(new OpenType[itemTypes.size()]);
				elementType =
						new CompositeType("CompositeData", "CompositeData", itemNamesArr, itemNamesArr, itemTypesArr);
			}

			return new ArrayType(1, elementType);
		} catch (OpenDataException e) {
			throw new IllegalArgumentException("Cannot create ArrayType. " + nodeName, e);
		}
	}

	@Override
	public Map> getOpenTypes() {
		return Collections.>singletonMap(name, arrayType);
	}

	@Override
	public Object aggregateAttribute(String attrName, List sources) {
		List> attributesFromAllElements = new ArrayList<>();
		Set visibleSubAttrs = subNode.getVisibleAttributes();
		for (Object source : sources) {
			List currentList = (List) fetcher.fetchFrom(source);
			if (currentList != null) {
				for (Object element : currentList) {
					Map attributesFromElement =
							subNode.aggregateAttributes(visibleSubAttrs, singletonList(element));

					attributesFromAllElements.add(attributesFromElement);
				}
			}
		}

		return attributesFromAllElements.size() > 0 ? createArrayFrom(attributesFromAllElements) : null;
	}

	private Object[] createArrayFrom(List> attributesFromAllElements) {
		OpenType arrayElementOpenType = arrayType.getElementOpenType();
		if (arrayElementOpenType instanceof ArrayType) {
			throw new RuntimeException("Multidimensional arrays are not supported");
		} else {
			try {
				Class elementClass = classOf(arrayType.getElementOpenType());
				Object[] array = (Object[]) Array.newInstance(elementClass, attributesFromAllElements.size());
				for (int i = 0; i < attributesFromAllElements.size(); i++) {
					Map attributesFromElement = attributesFromAllElements.get(i);
					array[i] = jmxCompatibleObjectOf(arrayElementOpenType, attributesFromElement);
				}
				return array;
			} catch (OpenDataException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private static Object jmxCompatibleObjectOf(OpenType openType, Map attributes)
			throws OpenDataException {
		if (openType instanceof SimpleType || openType instanceof TabularType) {
			checkArgument(attributes.size() == 1);
			return first(attributes.values());
		} else if (openType instanceof CompositeType) {
			CompositeType compositeType = (CompositeType) openType;
			return new CompositeDataSupport(compositeType, attributes);
		} else {
			throw new RuntimeException("There is no support for " + openType);
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public List getAllRefreshables(Object source) {
		if (!isListOfJmxRefreshables) {
			return emptyList();
		}

		List listRef = (List) fetcher.fetchFrom(source);
		return Collections.singletonList(new JmxRefreshable() {
			@Override
			public void refresh(long timestamp) {
				for (JmxRefreshable jmxRefreshableElement : listRef) {
					jmxRefreshableElement.refresh(timestamp);
				}
			}
		});
	}

	@Override
	public boolean isSettable(String attrName) {
		return false;
	}

	@Override
	public void setAttribute(String attrName, Object value, List targets) {
		throw new UnsupportedOperationException();
	}

	private static Class classOf(OpenType openType) {
		if (openType.equals(SimpleType.BOOLEAN)) {
			return Boolean.class;
		} else if (openType.equals(SimpleType.BYTE)) {
			return Byte.class;
		} else if (openType.equals(SimpleType.SHORT)) {
			return Short.class;
		} else if (openType.equals(SimpleType.CHARACTER)) {
			return Character.class;
		} else if (openType.equals(SimpleType.INTEGER)) {
			return Integer.class;
		} else if (openType.equals(SimpleType.LONG)) {
			return Long.class;
		} else if (openType.equals(SimpleType.FLOAT)) {
			return Float.class;
		} else if (openType.equals(SimpleType.DOUBLE)) {
			return Double.class;
		} else if (openType.equals(SimpleType.STRING)) {
			return String.class;
		} else if (openType instanceof CompositeType) {
			return CompositeData.class;
		} else if (openType instanceof TabularType) {
			return TabularData.class;
		}
		// ArrayType is not supported
		throw new IllegalArgumentException(format("OpenType \"%s\" cannot be converted to Class", openType));
	}
}