| /******************************************************************************* |
| * Copyright (c) 2011, 2012 VMware Inc. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * VMware Inc. - initial contribution |
| *******************************************************************************/ |
| |
| package org.eclipse.equinox.internal.region.management; |
| |
| import java.lang.management.ManagementFactory; |
| import java.util.*; |
| import java.util.concurrent.ConcurrentHashMap; |
| import javax.management.*; |
| import org.eclipse.equinox.internal.region.RegionLifecycleListener; |
| import org.eclipse.equinox.region.Region; |
| import org.eclipse.equinox.region.RegionDigraph; |
| import org.eclipse.equinox.region.management.ManageableRegion; |
| import org.eclipse.equinox.region.management.ManageableRegionDigraph; |
| import org.osgi.framework.*; |
| |
| /** |
| * {@link StandardManageableRegionDigraph} is a {@link ManageableRegionDigraph} that delegates to the |
| * {@link RegionDigraph}. |
| * <p /> |
| * |
| * <strong>Concurrent Semantics</strong><br /> |
| * Thread safe. |
| */ |
| public final class StandardManageableRegionDigraph implements ManageableRegionDigraph { |
| |
| private final RegionDigraph regionDigraph; |
| |
| private final String domain; |
| |
| private final RegionObjectNameCreator regionObjectNameCreator; |
| |
| private final Map<String, ManageableRegion> manageableRegions = new ConcurrentHashMap<String, ManageableRegion>(); |
| |
| private final BundleContext bundleContext; |
| |
| private final Object monitor = new Object(); |
| |
| private final MBeanServer mbeanServer; |
| |
| private final ObjectName mbeanName; |
| |
| private ServiceRegistration<RegionLifecycleListener> listenerRegistration; |
| |
| private final String frameworkUUID; |
| |
| private final RegionLifecycleListener regionLifecycleListener = new RegionLifecycleListener() { |
| |
| @Override |
| public void regionAdded(Region region) { |
| addRegion(region); |
| } |
| |
| @Override |
| public void regionRemoving(Region region) { |
| removeRegion(region); |
| } |
| |
| }; |
| |
| public StandardManageableRegionDigraph(RegionDigraph regionDigraph, String domain, BundleContext bundleContext) { |
| this.regionDigraph = regionDigraph; |
| this.domain = domain; |
| this.bundleContext = bundleContext; |
| this.mbeanServer = ManagementFactory.getPlatformMBeanServer(); |
| this.frameworkUUID = bundleContext.getProperty(Constants.FRAMEWORK_UUID); |
| this.regionObjectNameCreator = new RegionObjectNameCreator(domain, this.frameworkUUID); |
| String name = this.domain + ":type=RegionDigraph"; //$NON-NLS-1$ |
| if (frameworkUUID != null) |
| name += ",frameworkUUID=" + frameworkUUID; //$NON-NLS-1$ |
| try { |
| mbeanName = new ObjectName(name); |
| } catch (MalformedObjectNameException e) { |
| e.printStackTrace(); |
| throw new IllegalArgumentException("Invalid domain name '" + domain + "' resulting in an invalid object name '" + name + "'", e); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| } |
| |
| private void registerRegionLifecycleListener() { |
| synchronized (this.monitor) { |
| listenerRegistration = this.bundleContext.registerService(RegionLifecycleListener.class, regionLifecycleListener, null); |
| } |
| } |
| |
| private void unregisterRegionLifecycleListener() { |
| synchronized (this.monitor) { |
| listenerRegistration.unregister(); |
| } |
| } |
| |
| public void registerMBean() { |
| registerRegionLifecycleListener(); |
| synchronized (this.monitor) { |
| // The following alien call is unavoidable to ensure consistency. |
| Set<Region> regions = this.regionDigraph.getRegions(); |
| for (Region region : regions) { |
| addRegion(region); |
| } |
| } |
| |
| safelyRegisterMBean(this, mbeanName); |
| } |
| |
| public void unregisterMbean() { |
| unregisterRegionLifecycleListener(); |
| Collection<String> currentRegionNames; |
| synchronized (this.monitor) { |
| currentRegionNames = new ArrayList<String>(this.manageableRegions.keySet()); |
| } |
| for (String regionName : currentRegionNames) { |
| removeRegion(regionName); |
| } |
| try { |
| this.mbeanServer.unregisterMBean(this.mbeanName); |
| } catch (MBeanRegistrationException e) { |
| e.printStackTrace(); |
| throw new RuntimeException("Problem unregistering mbean", e); //$NON-NLS-1$ |
| } catch (InstanceNotFoundException e) { |
| // Something else unregistered the bean |
| } |
| } |
| |
| private void safelyRegisterMBean(Object mbean, ObjectName name) { |
| try { |
| try { |
| this.mbeanServer.registerMBean(mbean, name); |
| } catch (InstanceAlreadyExistsException e) { |
| // Recover as this happens when a JVM is reused. |
| this.mbeanServer.unregisterMBean(name); |
| this.mbeanServer.registerMBean(mbean, name); |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| throw new RuntimeException("MBean registration failed", e); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public ManageableRegion[] getRegions() { |
| List<ManageableRegion> regions = new ArrayList<ManageableRegion>(); |
| synchronized (this.monitor) { |
| for (ManageableRegion manageableRegion : this.manageableRegions.values()) { |
| regions.add(manageableRegion); |
| } |
| } |
| return regions.toArray(new ManageableRegion[regions.size()]); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public ManageableRegion getRegion(String regionName) { |
| return this.manageableRegions.get(regionName); |
| } |
| |
| void addRegion(Region region) { |
| StandardManageableRegion manageableRegion = new StandardManageableRegion(region, this, this.regionDigraph); |
| safelyRegisterMBean(manageableRegion, this.regionObjectNameCreator.getRegionObjectName(region.getName())); |
| synchronized (this.monitor) { |
| this.manageableRegions.put(region.getName(), manageableRegion); |
| } |
| } |
| |
| void removeRegion(Region region) { |
| removeRegion(region.getName()); |
| } |
| |
| private void removeRegion(String regionName) { |
| synchronized (this.monitor) { |
| this.manageableRegions.remove(regionName); |
| } |
| try { |
| this.mbeanServer.unregisterMBean(this.regionObjectNameCreator.getRegionObjectName(regionName)); |
| } catch (MBeanRegistrationException e) { |
| e.printStackTrace(); |
| throw new RuntimeException("Problem unregistering mbean", e); //$NON-NLS-1$ |
| } catch (InstanceNotFoundException e) { |
| // Something else unregistered the bean |
| } |
| } |
| |
| } |