/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal; import java.beans.IntrospectionException; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; import javax.management.InstanceNotFoundException; import javax.management.ObjectName; import org.apache.logging.log4j.Logger; import org.apache.geode.cache.Region; import org.apache.geode.distributed.DistributedMember; import org.apache.geode.internal.ClassLoadUtil; import org.apache.geode.internal.logging.LogService; import org.apache.geode.management.ManagementException; /** * Instance of this class is responsible for proxy creation/deletion etc. * * If a member is added/removed proxy factory is responsible for creating removing the corresponding * proxies for that member. * * It also maintains a proxy repository {@link MBeanProxyInfoRepository} for quick access to the * proxy instances * * */ public class MBeanProxyFactory { private static final Logger logger = LogService.getLogger(); /** * Proxy repository contains several indexes to search proxies in an efficient manner. */ private MBeanProxyInfoRepository proxyRepo; /** * For Future release */ private RemoteFilterChain remoteFilterChain; /** * Interface between GemFire federation layer and Java JMX layer */ private MBeanJMXAdapter jmxAdapter; private SystemManagementService service; /** * * @param remoteFilterChain remote chain to filter out remote members * @param jmxAdapter adapter to interface between JMX and GemFire * @param service management service */ public MBeanProxyFactory(RemoteFilterChain remoteFilterChain, MBeanJMXAdapter jmxAdapter, SystemManagementService service) { this.remoteFilterChain = remoteFilterChain; this.jmxAdapter = jmxAdapter; this.proxyRepo = new MBeanProxyInfoRepository(); this.service = service; } /** * Creates a single proxy and adds a {@link ProxyInfo} to proxy repository * {@link MBeanProxyInfoRepository} * * @param member {@link org.apache.geode.distributed.DistributedMember} * @param objectName {@link javax.management.ObjectName} of the Bean * @param monitoringRegion monitoring region containing the proxies * @throws ManagementException */ public void createProxy(DistributedMember member, ObjectName objectName, Region<String, Object> monitoringRegion, Object newVal) { try { /* * Check the complete filter chain to evaluate the applicability of the MBean */ if (remoteFilterChain.isFiltered(objectName, member, "")) { if (logger.isTraceEnabled()) { logger.trace("Returning from filter"); } return; } Class interfaceClass = ClassLoadUtil .classFromName(((FederationComponent) monitoringRegion.get(objectName.toString())) .getMBeanInterfaceClass()); Object object = MBeanProxyInvocationHandler.newProxyInstance(member, monitoringRegion, objectName, interfaceClass); jmxAdapter.registerMBeanProxy(object, objectName); if (logger.isDebugEnabled()) { logger.debug("Registered ObjectName : {}", objectName); } ProxyInfo proxyInfo = new ProxyInfo(interfaceClass, object, objectName); proxyRepo.addProxyToRepository(member, proxyInfo); service.afterCreateProxy(objectName, interfaceClass, object, (FederationComponent) newVal); if (logger.isDebugEnabled()) { logger.debug("Proxy Created for : {}", objectName); } } catch (ClassNotFoundException e) { throw new ManagementException(e); } catch (IntrospectionException e) { throw new ManagementException(e); } catch (ManagementException e) { throw e; } } /** * This method will create all the proxies for a given DistributedMember. It does not throw any * exception to its caller. It handles the error and logs error messages * * It will be called from GII or when a member joins the system * * @param member {@link org.apache.geode.distributed.DistributedMember} * @param monitoringRegion monitoring region containing the proxies */ public void createAllProxies(DistributedMember member, Region<String, Object> monitoringRegion) { if (logger.isDebugEnabled()) { logger.debug("Creating proxy for: {}", member.getId()); } /* * Check for member and server group filters if the member is filtered no need to proceed * further */ if (remoteFilterChain.isServerGroupFiltered("")) { if (logger.isTraceEnabled()) { logger.trace("Returning from server group filter"); } return; } if (remoteFilterChain.isManagedNodeFiltered(member)) { if (logger.isTraceEnabled()) { logger.trace("returning from managed node filter"); } return; } Set<String> mbeanNames = monitoringRegion.keySet(); Iterator<String> it = mbeanNames.iterator(); while (it.hasNext()) { ObjectName objectName = null; /* * This is for MBean filter check. If filtered MBean wont be registered */ if (remoteFilterChain.isRemoteMBeanFiltered(objectName)) { if (logger.isTraceEnabled()) { logger.trace("continue from remote MBEan node filter"); } continue; } try { objectName = ObjectName.getInstance(it.next()); if (logger.isDebugEnabled()) { logger.debug("Creating proxy for ObjectName: " + objectName.toString()); } createProxy(member, objectName, monitoringRegion, monitoringRegion.get(objectName.toString())); } catch (ManagementException e) { logger.warn("Create Proxy failed for {} with exception {}", objectName, e.getMessage(), e); continue; } catch (Exception e) { logger.warn("Create Proxy failed for {} with exception {}", objectName, e.getMessage(), e); continue; } } } /** * Removes all proxies for a given member * * @param member {@link org.apache.geode.distributed.DistributedMember} * @param monitoringRegion monitoring region containing the proxies */ public void removeAllProxies(DistributedMember member, Region<String, Object> monitoringRegion) { Set<Entry<String, Object>> entries = monitoringRegion.entrySet(); Iterator<Entry<String, Object>> entriesIt = entries.iterator(); if (logger.isDebugEnabled()) { logger.debug("Removing {} proxies for member {}", entries.size(), member.getId()); } while (entriesIt.hasNext()) { String key = null; Object val = null; try { Entry<String, Object> entry = entriesIt.next(); key = entry.getKey();// MBean Name in String format. val = entry.getValue(); // Federation Component ObjectName mbeanName = ObjectName.getInstance(key); removeProxy(member, mbeanName, val); } catch (Exception e) { if (!(e.getCause() instanceof InstanceNotFoundException)) { logger.warn("Remove Proxy failed for {} due to {}", key, e.getMessage(), e); } continue; } } } /** * Removes the proxy * * @param member {@link org.apache.geode.distributed.DistributedMember} * @param objectName {@link javax.management.ObjectName} of the Bean */ public void removeProxy(DistributedMember member, ObjectName objectName, Object oldVal) { try { if (logger.isDebugEnabled()) { logger.debug("Removing proxy for ObjectName: {}", objectName); } if (!remoteFilterChain.isRemoteMBeanFiltered(objectName)) { ProxyInfo proxyInfo = proxyRepo.findProxyInfo(objectName); proxyRepo.removeProxy(member, objectName); if (proxyInfo != null) { service.afterRemoveProxy(objectName, proxyInfo.getProxyInterface(), proxyInfo.getProxyInstance(), (FederationComponent) oldVal); } jmxAdapter.unregisterMBean(objectName); if (logger.isDebugEnabled()) { logger.debug("Removed proxy for ObjectName: {}", objectName); } } } catch (Exception e) { if (!(e.getCause() instanceof InstanceNotFoundException)) { logger.warn("Could not remove proxy for Member {} due to {}", member, e.getMessage(), e); } } } public void updateProxy(ObjectName objectName, ProxyInfo proxyInfo, Object newObject, Object oldObject) { try { if (proxyInfo != null) { Class interfaceClass = proxyInfo.getProxyInterface(); service.afterUpdateProxy(objectName, interfaceClass, proxyInfo.getProxyInstance(), (FederationComponent) newObject, (FederationComponent) oldObject); } } catch (Exception e) { throw new ManagementException(e); } } /** * Find a particular proxy instance for a {@link javax.management.ObjectName} , * {@link org.apache.geode.distributed.DistributedMember} and interface class If the proxy * interface does not implement the given interface class a {@link java.lang.ClassCastException}. * will be thrown * * @param objectName {@link javax.management.ObjectName} of the MBean * @param interfaceClass interface class implemented by proxy * @return an instance of proxy exposing the given interface */ public <T> T findProxy(ObjectName objectName, Class<T> interfaceClass) { return proxyRepo.findProxyByName(objectName, interfaceClass); } public ProxyInfo findProxyInfo(ObjectName objectName) { return proxyRepo.findProxyInfo(objectName); } /** * Find a set of proxies given a {@link org.apache.geode.distributed.DistributedMember} * * @param member {@link org.apache.geode.distributed.DistributedMember} * @return a set of {@link javax.management.ObjectName} */ public Set<ObjectName> findAllProxies(DistributedMember member) { return proxyRepo.findProxySet(member); } /** * This will return the last updated time of the proxyMBean * * @param objectName {@link javax.management.ObjectName} of the MBean * @return last updated time of the proxy */ public long getLastUpdateTime(ObjectName objectName) { ProxyInterface proxyObj = findProxy(objectName, ProxyInterface.class); return proxyObj.getLastRefreshedTime(); } }