This project has retired. For details please refer to its Attic page.
UDDIServiceCounter.java

UDDIServiceCounter.java

/*
 * Copyright 2001-2008 The Apache Software Foundation.
 * 
 * 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 org.apache.juddi.api.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.ReflectionException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.juddi.api.util.QueryStatus;
import org.apache.juddi.api.util.UDDIQuery;

/**
 * This class provides MBean functionality that offers metrics on UDDI service method invocations
 * and various management functions (documented by Alex O'Ree)
 * @author Tom Cunningham
 */
public class UDDIServiceCounter implements DynamicMBean, Serializable {

    private static Log log = LogFactory.getLog(UDDIServiceCounter.class);

    private Hashtable <String, LongHolder> queryProcessingTime;
    private Hashtable <String, IntHolder> totalQueryCounter;
    private Hashtable <String, IntHolder> successQueryCounter;
    private Hashtable <String, IntHolder> faultQueryCounter;

    private ObjectName listObjectName = null;
    
    private int totalApiCounter;
    private int successApiCounter;
    private int faultApiCounter;
    
    private static final String PROCESSING_TIME = "processing time";
    private static final String TOTAL_QUERIES = "total queries";
    private static final String SUCCESSFUL_QUERIES = "successful queries";
    private static final String FAILED_QUERIES = "failed queries";
    
    private static final String TOTAL_API_QUERIES = "Total API Queries";
    private static final String SUCCESSFUL_API_QUERIES = "Successful API Queries";
    private static final String FAILED_API_QUERIES = "Failed API Queries";
    
    public static final String RESET_COUNTER = "resetCounts";
        
    public void initList(Class klass, List<String> queries) {
        try {
            listObjectName = new ObjectName("apache.juddi:" + "counter=" + klass.getName());
        } catch (MalformedObjectNameException mone) {
            log.error(mone);
        }
        
        queryProcessingTime = new Hashtable<String,LongHolder>();
        totalQueryCounter = new Hashtable<String, IntHolder>();
        successQueryCounter = new Hashtable<String, IntHolder>();
        faultQueryCounter = new Hashtable<String, IntHolder>();
            
        for (String query : queries) {
            queryProcessingTime.put(query + " " +  PROCESSING_TIME, new LongHolder());
            totalQueryCounter.put(query + " " + TOTAL_QUERIES, new IntHolder());
            successQueryCounter.put(query + " " + SUCCESSFUL_QUERIES, new IntHolder());
            faultQueryCounter.put(query + " " + FAILED_QUERIES, new IntHolder());
        }
        
        totalApiCounter = 0;
        successApiCounter = 0;
        faultApiCounter = 0;

    }
    
    protected void registerMBean() {
        MBeanServer mbeanServer = null;
        
        mbeanServer = getServer();
        if (mbeanServer == null) {
            try {
//                mbeanServer = MBeanServerLocator.locateJBoss();
            } catch (IllegalStateException ise) {
                // If we can't find a JBoss MBeanServer, just return
                // Needed for unit tests
                return;
            }            
        }
        
        try {
        	if (! mbeanServer.isRegistered(listObjectName))
        		mbeanServer.registerMBean(this, listObjectName);
        } catch (InstanceAlreadyExistsException e) {
            log.warn("", e);
        } catch (MBeanRegistrationException e) {
            log.warn("", e);
        } catch (NotCompliantMBeanException e) {
            log.warn("", e);
        }   
    }
        
    private MBeanServer getServer() {
        MBeanServer mbserver = null;

        ArrayList mbservers = MBeanServerFactory.findMBeanServer(null);

        if (mbservers.size() > 0) {
          mbserver = (MBeanServer) mbservers.get(0);
        }

        if (mbserver != null) {
	  log.info("Found MBean server");
        } else {
          mbserver = MBeanServerFactory.createMBeanServer();
        } 

        return mbserver;
    }
    
    public void resetCounts() {
        for (String key : queryProcessingTime.keySet()) {
            queryProcessingTime.put(key, new LongHolder());
        }
        
        for (String key : totalQueryCounter.keySet()) {
            totalQueryCounter.put(key, new IntHolder());
        }
        
        for (String key : successQueryCounter.keySet()) {
            successQueryCounter.put(key, new IntHolder());
        }
        
        for (String key : faultQueryCounter.keySet()) {
            faultQueryCounter.put(key, new IntHolder());
        }
        
        totalApiCounter = 0;
        successApiCounter = 0;
        faultApiCounter = 0;

    }

    /**
     * This updates the performance metrics for a given service.
     * 
     * Note, as of jUDDI 3.2, procTime MUST be in milliseconds. Prior to 3.2 used nanoseconds
     * @param queryObject the item that was executed
     * @param queryStatus success or fail status
     * @param procTime Expects time in milliseconds
     */
    public synchronized void update(UDDIQuery queryObject, QueryStatus queryStatus, 
            long procTime) {        
        //log.info("Updating " + queryObject.getQuery() + " time " + procTime);
        String query = queryObject.getQuery();
        
        LongHolder totalProcTime = queryProcessingTime.get(query + " " +  PROCESSING_TIME);
        if (totalProcTime != null) {
            totalProcTime.value += procTime;
            totalApiCounter++;
        } else {
            throw new RuntimeException("Exception in Update : " + queryObject.getQuery() 
                    + " time " + procTime + " queryprocessingtime.size() + "
                    + queryProcessingTime.size());
        }
        
        IntHolder queryCounter = totalQueryCounter.get(query + " " + TOTAL_QUERIES);
        if (queryCounter != null) { 
            queryCounter.value++;
        } else {
            throw new RuntimeException("Exception in Update : " + queryObject.getQuery() 
                    + " time " + procTime + " totalQueryCounter.size() + "
                    + totalQueryCounter.size());
        }

        if (queryStatus == QueryStatus.SUCCESS) {
            IntHolder successQuery = successQueryCounter.get(query + " " + SUCCESSFUL_QUERIES);
            if (successQuery != null) {
                successQuery.value++;
                successApiCounter++;
            } else {
                throw new RuntimeException("Exception in Update : " + queryObject.getQuery() 
                        + " time " + procTime + " successQueryCounter.size() "
                        + successQueryCounter.size());
            }
        } else if (queryStatus == queryStatus.FAILED) {
            IntHolder faultQuery = faultQueryCounter.get(query + " " + FAILED_QUERIES);
            if (faultQuery != null) {
                faultQuery.value++;
                faultApiCounter++;
            } else {
                throw new RuntimeException("Exception in Update : " + queryObject.getQuery() 
                        + " time " + procTime + " faultQueryCounter.size() "
                        + faultQueryCounter.size());
            }            
        }        
    }
    
    @Override
    public Object getAttribute(String attribute)
            throws AttributeNotFoundException, MBeanException,
            ReflectionException {
        if (queryProcessingTime.containsKey(attribute)) {
            return queryProcessingTime.get(attribute);
        } else if (totalQueryCounter.containsKey(attribute)) {
            return totalQueryCounter.get(attribute);
        } else if (successQueryCounter.containsKey(attribute)) {
            return successQueryCounter.get(attribute);
        } else if (faultQueryCounter.containsKey(attribute)) {
            return faultQueryCounter.get(attribute);
        } else if (attribute.equals(TOTAL_API_QUERIES)) {
            return totalApiCounter;
        } else if (attribute.equals(SUCCESSFUL_API_QUERIES)) {
            return successApiCounter;
        } else if (attribute.equals(FAILED_API_QUERIES)) {
            return faultApiCounter;
        }
        return null;
    }

    @Override
    public void setAttribute(Attribute attribute)
            throws AttributeNotFoundException, InvalidAttributeValueException,
            MBeanException, ReflectionException {
        
    }

    @Override
    public AttributeList getAttributes(String[] attributes) {
        AttributeList attributeList = new AttributeList();

        attributeList.add(new Attribute(TOTAL_API_QUERIES, totalApiCounter));
        attributeList.add(new Attribute(SUCCESSFUL_API_QUERIES, successApiCounter));
        attributeList.add(new Attribute(FAILED_API_QUERIES, faultApiCounter));

        for (String key : queryProcessingTime.keySet()) {
            Attribute at = new Attribute(key, queryProcessingTime.get(key).toString());
            attributeList.add(at);
        }
                
        for (String key : totalQueryCounter.keySet()) {
            Attribute at = new Attribute(key, totalQueryCounter.get(key).toString());
            attributeList.add(at);
        }
        
        for (String key : successQueryCounter.keySet()) {
            Attribute at = new Attribute(key, successQueryCounter.get(key).toString());
            attributeList.add(at);
        }

        for (String key : faultQueryCounter.keySet()) {
            Attribute at = new Attribute(key, faultQueryCounter.get(key).toString());
            attributeList.add(at);
        }
        
        return attributeList;
    }

    @Override
    public AttributeList setAttributes(AttributeList attributes) {
        return null;
    }

    @Override
    public Object invoke(String actionName, Object[] params, String[] signature)
            throws MBeanException, ReflectionException {
        if (actionName.equalsIgnoreCase(RESET_COUNTER)) {
            resetCounts();
            return "Invoking the " + actionName + " on the lifecycle.";
        } else {
            throw new ReflectionException(new NoSuchMethodException(actionName));
        }
    }

    @Override
    public MBeanInfo getMBeanInfo() {
        // the extra 3 added are for totalApiQueries, faultApiQueries, and
        // successfulApiQueries
        int count = queryProcessingTime.size() + totalQueryCounter.size() +
            successQueryCounter.size() + faultQueryCounter.size() + 3;  

        MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[count];
        int counter = 0;

        attrs[counter] = new MBeanAttributeInfo(
                TOTAL_API_QUERIES, "java.lang.Integer", "Property " + TOTAL_API_QUERIES,
                true, false, false);
        counter++;
        
        attrs[counter] = new MBeanAttributeInfo(
                SUCCESSFUL_API_QUERIES, "java.lang.Integer", "Property " + SUCCESSFUL_API_QUERIES,
                true, false, false);
        counter++;
        
        attrs[counter] =  new MBeanAttributeInfo(
                FAILED_API_QUERIES, "java.lang.Integer", "Property " + FAILED_API_QUERIES,
                true, false, false);
        counter++;
        
        for (String key : queryProcessingTime.keySet()) {
            attrs[counter] = new MBeanAttributeInfo(
                    key, "java.lang.Double", "Property " + key, true, false, false);
            counter++;
        }

        for (String key : totalQueryCounter.keySet()) {
            attrs[counter] = new MBeanAttributeInfo(
                    key, "java.lang.Integer", "Property " + key, true, false, false);
            counter++;
        }

        for (String key : successQueryCounter.keySet()) {
            attrs[counter] = new MBeanAttributeInfo(
                    key, "java.lang.Integer", "Property " + key, true, false, false);
            counter++;
        }

        for (String key : faultQueryCounter.keySet()) {
            attrs[counter] = new MBeanAttributeInfo(
                    key, "java.lang.Integer", "Property " + key, true, false, false);
            counter++;
        }
        
        MBeanOperationInfo[] opers = {
                new MBeanOperationInfo(
                        RESET_COUNTER, "Reset the counter",
                        null, "void", MBeanOperationInfo.ACTION)
        };        
        
        return new MBeanInfo(this.getClass().getName(), "Service Counter MBean", 
                attrs, null, opers, null);
    }
    
    private static final class IntHolder implements Serializable
    {
            int value ;
            @Override
            public String toString() {
                    return Integer.toString(value);
            }
    }

    private static final class LongHolder implements Serializable
    {
            long value ;
            @Override
            public String toString() {
                    return Long.toString(value);
            }
    }
}