package example.productcodes;
import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeDataView;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
VisualVM@authorDaniel Fuchs
public class ProductCodes {
static <K, V> Map<K, V> newHashMap() {
return new HashMap<K, V>();
}
static <K, V> Map<K, V> newHashMap(Map<? extends K, ? extends V> map) {
return new HashMap<K, V>(map);
}
static <K, V> Map<K, V> newHashMap(int initialCapacity) {
return new HashMap<K, V>(initialCapacity);
}
public static interface RegisteredProduct {
public String getProductName();
public int getProductId();
}
public static interface ProductsDBData {
public Date getTimeStamp();
public Map<String, Integer> toProductsMap();
}
public static abstract class ProductsDBRecord implements ProductsDBData {
public abstract Date getTimeStamp();
public abstract Map<String, Integer> toProductsMap();
public static ProductsDBRecord from(CompositeData data) {
return ProductsDB.ProductsDBRecordImpl.from(data);
}
}
public static abstract class ProductsDBTable implements ProductsDBData {
public abstract Date getTimeStamp();
public abstract TabularData getProductsTable();
public abstract Map<String, Integer> toProductsMap();
public static ProductsDBTable from(CompositeData data) {
return ProductsDB.ProductsDBTableImpl.from(data);
}
}
public static interface ProductsDBMXBean {
public RegisteredProduct[] getRegisteredProducts()
throws InterruptedException;
public Map<String, Integer> getProductsMap()
throws InterruptedException;
public Map<String, RegisteredProduct> getRegisteredProductsMap()
throws InterruptedException;
public ProductsDBRecord getProductsDBRecord()
throws InterruptedException, OpenDataException;
public ProductsDBTable getProductsDBTable()
throws InterruptedException, OpenDataException;
@paramproductName@return
public int registerProduct(String productName)
throws InterruptedException;
@paramproductName@return@throwsIllegalArgumentException
public int removeProduct(String productName)
throws InterruptedException;
}
public static class ProductsDB implements ProductsDBMXBean {
private final Map<String, Integer> productMap;
private final ReadWriteLock lock;
private int productIdGenerator = 0;
private static final class Fields {
public static final String productName = "productName";
public static final String productId = "productId";
public static final String timeStamp = "timeStamp";
public static final String productTable = "productTable";
}
public ProductsDB() {
productMap = newHashMap();
lock = new ReentrantReadWriteLock();
}
public RegisteredProduct[] getRegisteredProducts()
throws InterruptedException {
if (!lock.readLock().tryLock(3, TimeUnit.SECONDS)) {
throw new InterruptedException("Resource locked. Retry later.");
}
try {
final RegisteredProduct[] registrations =
new RegisteredProduct[productMap.size()];
int count = 0;
for (Map.Entry<String, Integer> product:productMap.entrySet()) {
final String productName = product.getKey();
final int productId = product.getValue();
final RegisteredProduct
registered = new RegisteredProduct() {
public String getProductName() {return productName;}
public int getProductId() {return productId;}
};
registrations[count++] = registered;
}
return registrations;
} finally {
lock.readLock().unlock();
}
}
public Map<String, Integer> getProductsMap()
throws InterruptedException {
if (!lock.readLock().tryLock(3, TimeUnit.SECONDS)) {
throw new InterruptedException("Resource locked. Retry later.");
}
try {
return Collections.unmodifiableMap(productMap);
} finally {
lock.readLock().unlock();
}
}
public Map<String, RegisteredProduct> getRegisteredProductsMap()
throws InterruptedException {
if (!lock.readLock().tryLock(3, TimeUnit.SECONDS)) {
throw new InterruptedException("Resource locked. Retry later.");
}
try {
final RegisteredProduct[] uids = getRegisteredProducts();
final Map<String, RegisteredProduct> map =
newHashMap(uids.length);
for (RegisteredProduct u : uids) {
map.put(u.getProductName(), u);
}
return map;
} finally {
lock.readLock().unlock();
}
}
@return@throwsjava.lang.InterruptedException
@throwsjavax.management.openmbean.OpenDataException
public ProductsDBRecord getProductsDBRecord()
throws InterruptedException, OpenDataException {
if (!lock.readLock().tryLock(3, TimeUnit.SECONDS)) {
throw new InterruptedException("Resource locked. Retry later.");
}
try {
return new ProductsDBRecordImpl(productMap);
} finally {
lock.readLock().unlock();
}
}
@return@throwsjava.lang.InterruptedException
@throwsjavax.management.openmbean.OpenDataException
public ProductsDBTable getProductsDBTable()
throws InterruptedException, OpenDataException {
if (!lock.readLock().tryLock(3, TimeUnit.SECONDS)) {
throw new InterruptedException("Resource locked. Retry later.");
}
try {
return new ProductsDBTableImpl(productMap);
} finally {
lock.readLock().unlock();
}
}
public static class ProductsDBRecordImpl extends ProductsDBRecord
implements CompositeDataView {
private final Date timeStamp;
private final Map<String, Integer> productMap;
private ProductsDBRecordImpl(Map<String, Integer> productMap) {
this(productMap, new Date());
}
private ProductsDBRecordImpl(Map<String, Integer> productMap,
Date date) {
this.productMap = newHashMap(productMap);
this.timeStamp = date;
}
public Date getTimeStamp() {
return timeStamp;
}
public Map<String, Integer> toProductsMap() {
return productMap;
}
@return
public CompositeData toCompositeData(CompositeType ct) {
try {
final Map<String, Object> values =
newHashMap();
values.putAll(productMap);
values.put(Fields.timeStamp, getTimeStamp());
final String[] productNames =
productMap.keySet().
toArray(new String[productMap.size()]);
final String[] itemNames =
new String[productNames.length + 1];
System.arraycopy(productNames, 0, itemNames, 1,
productNames.length);
itemNames[0] = Fields.timeStamp;
final OpenType[] itemTypes =
new OpenType[productMap.size() + 1];
Arrays.fill(itemTypes, SimpleType.INTEGER);
itemTypes[0] = SimpleType.DATE;
final CompositeType type =
new CompositeType(
ct.getTypeName(),
ct.getDescription(),
itemNames, itemNames, itemTypes);
return new CompositeDataSupport(type, values);
} catch (RuntimeException x) {
throw x;
} catch (Exception x) {
throw new IllegalArgumentException(ct.getTypeName(), x);
}
}
@Override
public String toString() {
return "{" + Fields.timeStamp + "=" +
String.valueOf(timeStamp) +
", " + Fields.productTable + "=" +
String.valueOf(productMap) + "}";
}
public static ProductsDBRecordImpl from(CompositeData data) {
final Date date = (Date) data.get(Fields.timeStamp);
Map<String, Integer> products = newHashMap();
for (String key : data.getCompositeType().keySet()) {
if (key.equals(Fields.timeStamp)) {
continue;
}
products.put(key, (Integer) data.get(key));
}
return new ProductsDBRecordImpl(products, date);
}
}
public static class ProductsDBTableImpl extends ProductsDBTable
implements CompositeDataView {
private final Date timeStamp;
private final ProductsTable productTable;
private ProductsDBTableImpl(Map<String, Integer> productMap) {
this(productMap, new Date());
}
private ProductsDBTableImpl(Map<String, Integer> productMap,
Date timeStamp) {
this.productTable = new ProductsTable(productMap);
this.timeStamp = timeStamp;
}
@Override
public Date getTimeStamp() {
return timeStamp;
}
@Override
public TabularData getProductsTable() {
return productTable.toTabularData();
}
@Override
public Map<String, Integer> toProductsMap() {
return productTable.toProductsMap();
}
@Override
public String toString() {
return "{" + Fields.timeStamp + "=" +
String.valueOf(timeStamp) +
", " + Fields.productTable + "=" +
String.valueOf(productTable) + "}";
}
@return
public CompositeData toCompositeData(CompositeType ct) {
try {
final TabularData table = productTable.toTabularData();
final String[] itemNames = {
Fields.timeStamp, Fields.productTable
};
final OpenType[] itemTypes = {SimpleType.DATE,
table.getTabularType()
};
final CompositeType type =
new CompositeType( ct.getTypeName(),
ct.getDescription(),
itemNames, itemNames, itemTypes);
final Object[] itemValues = {timeStamp, table};
return new CompositeDataSupport(type,itemNames,itemValues);
} catch (RuntimeException x) {
throw x;
} catch (Exception x) {
throw new IllegalArgumentException(ct.getTypeName(), x);
}
}
public static ProductsDBTableImpl from(CompositeData data) {
final Date date = (Date) data.get(Fields.timeStamp);
Map<String, Integer> products = newHashMap();
final TabularData productTable =
(TabularData) data.get(Fields.productTable);
for (CompositeData val :
(Collection<CompositeData>) productTable.values()) {
products.put((String) val.get(Fields.productName),
(Integer) val.get(Fields.productId));
}
return new ProductsDBTableImpl(products, date);
}
}
private static class ProductsTable {
private static volatile CompositeType rowType = null;
private static volatile TabularType tabularType = null;
private final TabularDataSupport table;
public ProductsTable(Map<String, Integer> productMap) {
table = new TabularDataSupport(getProductsTableTabularType());
for (Map.Entry<String, Integer> e : productMap.entrySet()) {
table.put(newProductRow(e.getKey(), e.getValue()));
}
}
@return
public TabularData toTabularData() {
return table;
}
public Map<String, Integer> toProductsMap() {
final Map<String, Integer> map = newHashMap();
for (Object d : table.values()) {
final CompositeData cd = (CompositeData) d;
map.put((String) cd.get(Fields.productName),
(Integer) cd.get(Fields.productId));
}
return map;
}
@return
private CompositeData newProductRow(String productName,
int productId) {
try {
final String[] itemNames = {
Fields.productName, Fields.productId
};
return new CompositeDataSupport(getProductsTableRowType(),
itemNames, new Object[]{productName, productId});
} catch (OpenDataException x) {
throw new IllegalArgumentException(
"Cannot construct ProductsTable", x);
}
}
@Override
public String toString() {
StringBuilder b = new StringBuilder().append("{");
String start = "{";
for (Object d : table.values()) {
b.append(start).
append(Fields.productName).append("=").
append(((CompositeData) d).get(Fields.productName)).
append(", ").
append(Fields.productId).append("=").
append(((CompositeData) d).get(Fields.productId)).
append("}");
start = ", {";
}
return b.append("}").toString();
}
private static CompositeType getProductsTableRowType() {
if (rowType != null) {
return rowType;
}
try {
final String[] itemNames = {
Fields.productName, Fields.productId
};
final OpenType[] itemTypes =
{SimpleType.STRING, SimpleType.INTEGER};
rowType = new CompositeType(
RegisteredProduct.class.getName(),
"registered product record", itemNames,
itemNames, itemTypes);
return rowType;
} catch (OpenDataException x) {
throw new IllegalArgumentException(
"Cannot construct ProductsTable", x);
}
}
private static TabularType getProductsTableTabularType() {
if (tabularType != null) {
return tabularType;
}
try {
tabularType = new TabularType(ProductsTable.class.getName(),
"product table", getProductsTableRowType(),
new String[]{Fields.productName});
return tabularType;
} catch (OpenDataException x) {
throw new IllegalArgumentException(
"Cannot construct ProductsTable", x);
}
}
}
@paramproductName
public int registerProduct(String productName)
throws InterruptedException {
if (!lock.writeLock().tryLock(3, TimeUnit.SECONDS)) {
throw new InterruptedException("Resource locked. Retry later.");
}
try {
if (productMap.containsKey(productName)) {
throw new IllegalArgumentException(productName+
" already exists");
}
productMap.put(productName, productIdGenerator++);
return productMap.get(productName);
} finally {
lock.writeLock().unlock();
}
}
@paramproductName
public int removeProduct(String productName)
throws InterruptedException {
if (!lock.writeLock().tryLock(3, TimeUnit.SECONDS)) {
throw new InterruptedException("Resource locked. Retry later.");
}
try {
if (!productMap.containsKey(productName)) {
throw new IllegalArgumentException(
"product "+productName+" does not exists");
}
return productMap.remove(productName);
} finally {
lock.writeLock().unlock();
}
}
}
public static void main(String[] args) throws Exception {
final MBeanServer platform =
ManagementFactory.getPlatformMBeanServer();
final ObjectName mbeanName = new ObjectName("example:type=ProductsDB");
platform.registerMBean(new ProductsDB(), mbeanName);
ProductsDBMXBean productsDB =
JMX.newMXBeanProxy(platform, mbeanName, ProductsDBMXBean.class);
productsDB.registerProduct("foo");
productsDB.registerProduct("bar");
System.out.println("Got products DB record: "+
productsDB.getProductsDBRecord());
System.out.println("Got products DB table: "+
productsDB.getProductsDBTable());
System.out.println("Strike 'Enter' to exit... ");
System.in.read();
}
}
|