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

io.datakernel.jmx.AttributeNodeForPojo 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.OpenType;
import java.util.*;

import static io.datakernel.util.JmxUtils.filterNulls;
import static io.datakernel.util.Preconditions.checkNotNull;
import static java.util.Collections.singletonList;

final class AttributeNodeForPojo implements AttributeNode {
	private static final char ATTRIBUTE_NAME_SEPARATOR = '_';

	private final String name;
	private final String description;
	private final ValueFetcher fetcher;
	private final JmxReducer reducer;
	private final Map fullNameToNode;
	private final List subNodes;
	private boolean visible;

	public AttributeNodeForPojo(String name, String description, boolean visible,
	                            ValueFetcher fetcher, JmxReducer reducer,
	                            List subNodes) {
		this.name = name;
		this.description = description;
		this.visible = visible;
		this.fetcher = fetcher;
		this.reducer = reducer;
		this.fullNameToNode = createFullNameToNodeMapping(name, subNodes);
		this.subNodes = subNodes;
	}

	private static Map createFullNameToNodeMapping(String name,
	                                                                      List subNodes) {
		Map fullNameToNodeMapping = new HashMap<>();
		for (AttributeNode subNode : subNodes) {
			Set currentSubAttrNames = subNode.getAllAttributes();
			for (String currentSubAttrName : currentSubAttrNames) {
				String currentAttrFullName = addPrefix(currentSubAttrName, name);
				if (fullNameToNodeMapping.containsKey(currentAttrFullName)) {
					throw new IllegalArgumentException(
							"There are several attributes with same name: " + currentSubAttrName);
				}
				fullNameToNodeMapping.put(currentAttrFullName, subNode);
			}
		}
		return fullNameToNodeMapping;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public Set getAllAttributes() {
		return fullNameToNode.keySet();
	}

	@Override
	public Set getVisibleAttributes() {
		if (!visible) {
			return Collections.emptySet();
		} else {
			Set allVisibleAttrs = new HashSet<>();
			for (AttributeNode subNode : subNodes) {
				Set visibleSubAttrs = subNode.getVisibleAttributes();
				for (String visibleSubAttr : visibleSubAttrs) {
					String visibleAttr = addPrefix(visibleSubAttr);
					allVisibleAttrs.add(visibleAttr);
				}
			}
			return allVisibleAttrs;
		}
	}

	@Override
	public Map> getDescriptions() {
		Map> nameToDescriptions = new HashMap<>();
		for (AttributeNode subNode : subNodes) {
			Map> currentSubNodeDescriptions = subNode.getDescriptions();
			for (String subNodeAttrName : currentSubNodeDescriptions.keySet()) {
				String resultAttrName = addPrefix(subNodeAttrName);
				Map curDescriptions = new LinkedHashMap<>();
				if (description != null) {
					curDescriptions.put(name, description);
				}
				curDescriptions.putAll(currentSubNodeDescriptions.get(subNodeAttrName));
				nameToDescriptions.put(resultAttrName, curDescriptions);
			}
		}
		return nameToDescriptions;
	}

	@Override
	public Map> getOpenTypes() {
		Map> allTypes = new HashMap<>();
		for (AttributeNode subNode : subNodes) {
			Map> subAttrTypes = subNode.getOpenTypes();
			for (String subAttrName : subAttrTypes.keySet()) {
				OpenType attrType = subAttrTypes.get(subAttrName);
				String attrName = addPrefix(subAttrName);
				allTypes.put(attrName, attrType);
			}
		}
		return allTypes;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Map aggregateAttributes(Set attrNames, List sources) {
		checkNotNull(sources);
		checkNotNull(attrNames);
		List notNullSources = filterNulls(sources);
		if (notNullSources.size() == 0 || attrNames.isEmpty()) {
			Map nullMap = new HashMap<>();
			for (String attrName : attrNames) {
				nullMap.put(attrName, null);
			}
			return nullMap;
		}

		Map> groupedAttrs = groupBySubnode(attrNames);

		List subsources;
		if (notNullSources.size() == 1 || reducer == null) {
			subsources = fetchInnerPojos(notNullSources);
		} else {
			Object reduced = reducer.reduce(fetchInnerPojos(sources));
			subsources = singletonList(reduced);
		}

		Map aggregatedAttrs = new HashMap<>();
		for (AttributeNode subnode : groupedAttrs.keySet()) {
			Set subAttrNames = groupedAttrs.get(subnode);
			Map subAttrs;

			try {
				subAttrs = subnode.aggregateAttributes(subAttrNames, subsources);
			} catch (Exception | AssertionError e) {
				for (String subAttrName : subAttrNames) {
					aggregatedAttrs.put(addPrefix(subAttrName), e);
				}
				continue;
			}

			for (String subAttrName : subAttrs.keySet()) {
				Object subAttrValue = subAttrs.get(subAttrName);
				aggregatedAttrs.put(addPrefix(subAttrName), subAttrValue);
			}
		}

		return aggregatedAttrs;
	}

	private List fetchInnerPojos(List outerPojos) {
		List innerPojos = new ArrayList<>(outerPojos.size());
		for (Object outerPojo : outerPojos) {
			Object pojo = fetcher.fetchFrom(outerPojo);
			if (pojo != null) {
				innerPojos.add(pojo);
			}
		}
		return innerPojos;
	}

	private Map> groupBySubnode(Set attrNames) {
		Map> selectedSubnodes = new HashMap<>();
		for (String attrName : attrNames) {
			AttributeNode subnode = fullNameToNode.get(attrName);
			Set subnodeAttrs = selectedSubnodes.get(subnode);
			if (subnodeAttrs == null) {
				subnodeAttrs = new HashSet<>();
				selectedSubnodes.put(subnode, subnodeAttrs);
			}
			String adjustedName = removePrefix(attrName);
			subnodeAttrs.add(adjustedName);
		}
		return selectedSubnodes;
	}

	private String removePrefix(String attrName) {
		String adjustedName;
		if (name.isEmpty()) {
			adjustedName = attrName;
		} else {
			adjustedName = attrName.substring(name.length(), attrName.length());
			if (adjustedName.length() > 0) {
				adjustedName = adjustedName.substring(1, adjustedName.length()); // remove ATTRIBUTE_NAME_SEPARATOR
			}
		}
		return adjustedName;
	}

	private String addPrefix(String attrName) {
		return addPrefix(attrName, name);
	}

	private static String addPrefix(String attrName, String prefix) {
		if (attrName.isEmpty()) {
			return prefix;
		}

		String actualPrefix = prefix.isEmpty() ? "" : prefix + ATTRIBUTE_NAME_SEPARATOR;
		return actualPrefix + attrName;
	}

	@Override
	public List getAllRefreshables(Object source) {
		Object pojo = fetcher.fetchFrom(source);

		if (pojo == null) {
			return Collections.emptyList();
		}

		if (pojo instanceof JmxRefreshable) {
			return singletonList(((JmxRefreshable) pojo));
		} else {
			List allJmxRefreshables = new ArrayList<>();
			for (AttributeNode attributeNode : subNodes) {
				List subNodeRefreshables = attributeNode.getAllRefreshables(pojo);
				allJmxRefreshables.addAll(subNodeRefreshables);
			}
			return allJmxRefreshables;
		}
	}

	@Override
	public final boolean isSettable(String attrName) {
		if (!fullNameToNode.containsKey(attrName)) {
			throw new IllegalArgumentException("There is no attribute with name: " + attrName);
		}

		AttributeNode appropriateSubNode = fullNameToNode.get(attrName);
		return appropriateSubNode.isSettable(removePrefix(attrName));
	}

	@Override
	public final void setAttribute(String attrName, Object value, List targets) throws SetterException {
		checkNotNull(targets);
		List notNullTargets = filterNulls(targets);
		if (notNullTargets.size() == 0) {
			return;
		}

		if (!fullNameToNode.containsKey(attrName)) {
			throw new IllegalArgumentException("There is no attribute with name: " + attrName);
		}

		AttributeNode appropriateSubNode = fullNameToNode.get(attrName);
		appropriateSubNode.setAttribute(removePrefix(attrName), value, fetchInnerPojos(targets));
	}

	@Override
	public boolean isVisible() {
		return visible;
	}

	@Override
	public void setVisible(String attrName) {
		if (attrName.equals(name)) {
			this.visible = true;
			return;
		}

		if (!fullNameToNode.containsKey(attrName)) {
			throw new IllegalArgumentException("There is no attribute with name: " + attrName);
		}

		AttributeNode appropriateSubNode = fullNameToNode.get(attrName);
		appropriateSubNode.setVisible(removePrefix(attrName));
	}

	@Override
	public void hideNullPojos(List sources) {
		List innerPojos = fetchInnerPojos(sources);
		if (innerPojos.size() == 0) {
			this.visible = false;
			return;
		}

		for (AttributeNode subNode : subNodes) {
			subNode.hideNullPojos(innerPojos);
		}
	}

	@SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
	@Override
	public void applyModifier(String attrName, AttributeModifier modifier, List target) {
		if (attrName.equals(name)) {
			AttributeModifier attrModifierRaw = modifier;
			List attributes = fetchInnerPojos(target);
			for (Object attribute : attributes) {
				attrModifierRaw.apply(attribute);
			}
			return;
		}

		for (String fullAttrName : fullNameToNode.keySet()) {
			if (flattenedAttrNameContainsNode(fullAttrName, attrName)) {
				AttributeNode appropriateSubNode = fullNameToNode.get(fullAttrName);
				appropriateSubNode.applyModifier(removePrefix(attrName), modifier, fetchInnerPojos(target));
				return;
			}
		}

		if (!fullNameToNode.containsKey(attrName)) {
			throw new IllegalArgumentException("There is no attribute with name: " + attrName);
		}
	}

	private static boolean flattenedAttrNameContainsNode(String flattenedAttrName, String nodeName) {
		return flattenedAttrName.startsWith(nodeName) &&
				(flattenedAttrName.length() == nodeName.length() ||
						flattenedAttrName.charAt(nodeName.length()) == ATTRIBUTE_NAME_SEPARATOR);

	}
}