package com.github.lindenb.jvarkit.tools.jmx; import java.text.DecimalFormat; import java.text.NumberFormat; import htsjdk.samtools.util.Locatable; import javax.management.Attribute; import javax.management.AttributeChangeNotification; import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.DynamicMBean; import javax.management.InvalidAttributeValueException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanConstructorInfo; import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; import javax.management.NotificationBroadcasterSupport; import javax.management.ReflectionException; import javax.management.RuntimeOperationsException; /* http://docs.oracle.com/cd/E19698-01/816-7609/6mdjrf83d/index.html */ public class LocatableStreamInfo extends NotificationBroadcasterSupport implements DynamicMBean { public enum Status{IDLE,RUNNING,BREAK,ABORT}; private String projectName=""; private String lastPosition=""; private long startMillisec =-1L; private long countRecords=0L; private Status control=Status.IDLE; public LocatableStreamInfo(String projectName) { this.projectName=projectName; } public LocatableStreamInfo() { this("undefined"); } public String getProjectName() { return projectName; } public void setProjectName(String projectName) { this.projectName = projectName; } public void setLastPosition(String lastPosition) { this.lastPosition = lastPosition; } public String getLastPosition() { return lastPosition; } public String getDuration() { if(this.startMillisec<0L) return ""; NumberFormat timeFmt = new DecimalFormat("00"); long seconds = (System.currentTimeMillis() - this.startMillisec) / 1000; final long s = seconds % 60; final long allMinutes = seconds / 60; final long m = allMinutes % 60; final long h = allMinutes / 60; return timeFmt.format(h) + ":" + timeFmt.format(m) + ":" + timeFmt.format(s); } public long getCount() { return countRecords; } public String getState() { return this.control.name(); } public Status watch(Locatable locatable) { if(this.startMillisec<0L) { synchronized (LocatableStreamInfo.class) { this.startMillisec = System.currentTimeMillis(); if(this.control.equals(Status.IDLE)) this.control= Status.RUNNING; } } if(locatable.getContig()!=null) { this.lastPosition = locatable.getContig()+":"+locatable.getStart(); } else { this.lastPosition = "unmapped"; } this.countRecords++; /** no need to send messages sendNotification(new AttributeChangeNotification(this, 0, System.currentTimeMillis(), "Chromosome", "Chromosome", "java.lang.String", locatable.getContig(), prevContig==null?".":prevContig )); prevContig=locatable.getContig(); */ return this.control; } /* metadata information about attributes and operations. */ private MBeanInfo dMBeanInfo = buildDynamicMBeanInfo(); private MBeanInfo buildDynamicMBeanInfo() { return new MBeanInfo( LocatableStreamInfo.class.getName(), "Mon premier MBean Dynamic", new MBeanAttributeInfo[]{ new MBeanAttributeInfo("ProjectName","java.lang.String","Project Name", true,false,false), new MBeanAttributeInfo("LastPosition","java.lang.String","Last Genomic Position", true,false,false), new MBeanAttributeInfo("Duration","java.lang.String","Duration", true,false,false), new MBeanAttributeInfo("Count","java.lang.Long","Number of records seen so far", true,false,false), new MBeanAttributeInfo("State","java.lang.String","Streaming State (IDLE/RUNNING/BREAK/ABORT)", true,false,false), }, new MBeanConstructorInfo[]{ new MBeanConstructorInfo( "SimpleDynamic", "SimpleDynamic", new MBeanParameterInfo[0] ) }, new MBeanOperationInfo[]{ new MBeanOperationInfo("doAbort", "Abort the loop with error", new MBeanParameterInfo[0],Void.TYPE.getName(),MBeanOperationInfo.ACTION), new MBeanOperationInfo("doBreak", "Break the loop and continue", new MBeanParameterInfo[0],Void.TYPE.getName(),MBeanOperationInfo.ACTION), }, null); } @Override public synchronized Object getAttribute(String attribute_name) throws AttributeNotFoundException, MBeanException, ReflectionException { // Check attribute_name to avoid NullPointerException later on if (attribute_name == null) throw new RuntimeOperationsException(new IllegalArgumentException("attName cannot be null")); // Call the corresponding getter for a recognized attribute_name if (attribute_name.equals("ProjectName")) return getProjectName(); if (attribute_name.equals("LastPosition")) return getLastPosition(); if (attribute_name.equals("Duration")) return getDuration(); if (attribute_name.equals("Count")) return getCount(); if (attribute_name.equals("State")) return getState(); // If attribute_name has not been recognized throw(new AttributeNotFoundException( "Cannot find " + attribute_name + " attribute in " + LocatableStreamInfo.class.getName())); } @Override public synchronized void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { // Check attribute to avoid NullPointerException later on if (attribute == null) { throw new RuntimeOperationsException( new IllegalArgumentException("Attribute cannot be null"), "Cannot invoke a setter of " + LocatableStreamInfo.class.getName() + " with null attribute"); } throw new AttributeNotFoundException( "Attribute " + attribute.getName() + " read only or not found in " + this.getClass().getName()); } @Override public synchronized AttributeList getAttributes(String[] attributeNames) { if (attributeNames == null) { throw new RuntimeOperationsException( new IllegalArgumentException( "attributeNames[] cannot be null"), "Cannot invoke a getter of " + LocatableStreamInfo.class.getName()); } AttributeList resultList = new AttributeList(); // build the result attribute list for (String attName:attributeNames) { try { Object value = getAttribute(attName); resultList.add(new Attribute(attName,value)); } catch (Exception e) { e.printStackTrace(); } } return(resultList); } @Override public synchronized AttributeList setAttributes(AttributeList attributes) { // Check attributes to avoid NullPointerException later on if (attributes == null) { throw new RuntimeOperationsException( new IllegalArgumentException( "AttributeList attributes cannot be null"), "Cannot invoke a setter of " + LocatableStreamInfo.class.getName()); } AttributeList resultList = new AttributeList(); // try to set each attribute and add to result list if successful for (Object i: attributes) { Attribute attr = (Attribute) i; try { setAttribute(attr); String name = attr.getName(); Object value = getAttribute(name); resultList.add(new Attribute(name,value)); } catch(Exception e) { e.printStackTrace(); } } return(resultList); } @Override public synchronized Object invoke(String operationName, Object[] params, String[] signature) throws MBeanException, ReflectionException { // Check operationName to avoid NullPointerException later on if (operationName == null) { throw new RuntimeOperationsException( new IllegalArgumentException( "Operation name cannot be null"), "Cannot invoke a null operation in " + LocatableStreamInfo.class.getName()); } // Call the corresponding operation for a recognized name if (operationName.equals("doBreak")){ // this code is specific to the internal "reset" method: doBreak(); // no parameters to check return null; // and no return value }else if (operationName.equals("doAbort")){ // this code is specific to the internal "reset" method: doAbort(); // no parameters to check return null; // and no return value } else { // unrecognized operation name: throw new ReflectionException( new NoSuchMethodException(operationName), "Cannot find the operation " + operationName + " in " + LocatableStreamInfo.class.getName()); } } @Override public MBeanInfo getMBeanInfo() { return dMBeanInfo; } private synchronized void setControl(Status ctrl) { if(this.control.equals(Status.ABORT)) return; if(this.control.equals(Status.BREAK) && !ctrl.equals(Status.ABORT)) return; AttributeChangeNotification acn = new AttributeChangeNotification(this, 0, System.currentTimeMillis(), "State changed", "State", "java.lang.String", this.control.name(), ctrl.name() ); this.control=ctrl; sendNotification(acn); } public synchronized void doBreak() { setControl(Status.BREAK); } public synchronized void doAbort() { setControl(Status.ABORT); } }