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

io.datakernel.jmx.AttributeNodeForMap 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.util.*;

import static io.datakernel.util.CollectionUtils.first;
import static io.datakernel.util.Preconditions.checkArgument;
import static java.util.Collections.emptyList;

final class AttributeNodeForMap extends AttributeNodeForLeafAbstract {
	private static final String KEY_COLUMN_NAME = "> key";
	private static final String VALUE_COLUMN_NAME = "value";
	private static final String EMPTY_COLUMN_NAME = "default";
	private static final String ROW_TYPE_NAME = "RowType";
	private static final String TABULAR_TYPE_NAME = "TabularType";

	private final AttributeNode subNode;
	private final TabularType tabularType;
	private final boolean isMapOfJmxRefreshable;

	public AttributeNodeForMap(String name, String description, boolean visible,
	                           ValueFetcher fetcher, AttributeNode subNode, boolean isMapOfJmxRefreshable) {
		super(name, description, fetcher, visible);
		checkArgument(!name.isEmpty(), "Map attribute cannot have empty name");
		this.tabularType = createTabularType(subNode, name);
		this.subNode = subNode;
		this.isMapOfJmxRefreshable = isMapOfJmxRefreshable;
	}

	private static TabularType createTabularType(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);
		}

		Map> attrNameToType = new HashMap<>();
		attrNameToType.put(KEY_COLUMN_NAME, SimpleType.STRING);
		if (visibleAttrs.size() == 1) {
			String attrName = first(visibleAttrs);
			OpenType attrType = attrTypes.get(attrName);
			String adjustedAttrName = attrName.isEmpty() ? VALUE_COLUMN_NAME : attrName;
			attrNameToType.put(adjustedAttrName, attrType);
		} else {
			for (String attrName : visibleAttrs) {
				OpenType attrType = attrTypes.get(attrName);
				String adjustedAttrName = attrName.isEmpty() ? EMPTY_COLUMN_NAME : attrName;

				if (attrNameToType.containsKey(adjustedAttrName)) {
					throw new IllegalArgumentException("In case of empty attribute name there must not be another " +
							"empty attribute and attribute with name \"default\"." + nodeName);
				}

				attrNameToType.put(attrName, attrType);
			}
		}

		List columnNames = new ArrayList<>();
		List> columnTypes = new ArrayList<>();
		for (String subAttrName : attrNameToType.keySet()) {
			OpenType subAttrType = attrNameToType.get(subAttrName);
			columnNames.add(subAttrName);
			columnTypes.add(subAttrType);
		}
		String[] columnNamesArr = columnNames.toArray(new String[columnNames.size()]);
		OpenType[] columnTypesArr = columnTypes.toArray(new OpenType[columnTypes.size()]);

		try {
			return new TabularType(
					TABULAR_TYPE_NAME,
					TABULAR_TYPE_NAME,
					new CompositeType(ROW_TYPE_NAME, ROW_TYPE_NAME, columnNamesArr, columnNamesArr, columnTypesArr),
					new String[]{KEY_COLUMN_NAME}
			);
		} catch (OpenDataException e) {
			throw new IllegalArgumentException("Cannot create TabularType. " + nodeName, e);
		}
	}

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

	@Override
	public Object aggregateAttribute(String attrName, List sources) {
		Map> groupedByKey = fetchMapsAndGroupEntriesByKey(sources);

		if (groupedByKey.size() == 0) {
			return null;
		}

		TabularDataSupport tdSupport = new TabularDataSupport(tabularType);
		Set visibleSubAttrs = subNode.getVisibleAttributes();
		for (Object key : groupedByKey.keySet()) {
			List group = groupedByKey.get(key);
			Map aggregatedGroup =
					subNode.aggregateAttributes(visibleSubAttrs, group);
			try {
				tdSupport.put(createTabularDataRow(key.toString(), aggregatedGroup));
			} catch (OpenDataException e) {
				throw new RuntimeException(e);
			}
		}
		return tdSupport.size() > 0 ? tdSupport : null;
	}

	private CompositeData createTabularDataRow(String key, Map attributes) throws OpenDataException {
		Map allAttributes = new HashMap<>(attributes.size() + 1);
		if (attributes.size() == 1) {
			String attrName = first(attributes.keySet());
			Object attrValue = attributes.get(attrName);
			String valueColumnName = attrName.isEmpty() ? VALUE_COLUMN_NAME : attrName;
			allAttributes.put(valueColumnName, attrValue);
		} else {
			if (attributes.containsKey("")) {
				Object emptyColumnValue = attributes.get("");
				attributes.remove("");
				attributes.put(EMPTY_COLUMN_NAME, emptyColumnValue);
			}

			allAttributes.putAll(attributes);
		}
		allAttributes.put(KEY_COLUMN_NAME, key);
		return new CompositeDataSupport(tabularType.getRowType(), allAttributes);
	}

	private Map> fetchMapsAndGroupEntriesByKey(List pojos) {
		List> listOfMaps = new ArrayList<>();
		for (Object pojo : pojos) {
			Map map = (Map) fetcher.fetchFrom(pojo);
			if (map != null && map.size() > 0) {
				listOfMaps.add(map);
			}
		}

		Map> grouped = new HashMap<>();
		for (Map currentMap : listOfMaps) {
			for (Object key : currentMap.keySet()) {
				if (!grouped.containsKey(key)) {
					grouped.put(key, new ArrayList<>());
				}
				grouped.get(key).add(currentMap.get(key));
			}
		}
		return grouped;
	}

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

		Map mapRef = ((Map) fetcher.fetchFrom(source));
		return Collections.singletonList(new JmxRefreshable() {
			@Override
			public void refresh(long timestamp) {
				for (JmxRefreshable jmxRefreshableValue : mapRef.values()) {
					jmxRefreshableValue.refresh(timestamp);
				}
			}
		});
	}

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

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