All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.internal.management.resources.AbstractManagementResource Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2022, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * https://oss.oracle.com/licenses/upl.
 */
package com.tangosol.internal.management.resources;

import com.oracle.coherence.common.base.Exceptions;
import com.oracle.coherence.common.base.Logger;

import com.tangosol.internal.health.HealthCheckWrapperMBean;
import com.tangosol.internal.http.HttpException;
import com.tangosol.internal.http.HttpRequest;
import com.tangosol.internal.http.QueryParameters;
import com.tangosol.internal.http.RequestRouter;
import com.tangosol.internal.http.Response;

import com.tangosol.internal.management.Converter;
import com.tangosol.internal.management.EntityMBeanResponse;
import com.tangosol.internal.management.MBeanResponse;
import com.tangosol.net.management.MapJsonBodyHandler;
import com.tangosol.net.CacheFactory;

import com.tangosol.net.Cluster;

import com.tangosol.net.management.MBeanAccessor;
import com.tangosol.net.management.MBeanAccessor.QueryBuilder;
import com.tangosol.net.management.MBeanServerProxy;
import com.tangosol.net.management.Registry;

import com.tangosol.util.Base;
import com.tangosol.util.Filter;
import com.tangosol.util.Filters;
import com.tangosol.util.ValueExtractor;

import java.net.URI;
import java.net.URISyntaxException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.tangosol.util.WrapperException;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.RuntimeMBeanException;

/**
 * The base resource for Coherence management resources.
 *
 * @author sr  2017.08.21
 * @author Jonathan Knight  2022.01.25
 * @author Gunnar Hillert  2022.05.13
 *
 * @since 12.2.1.4
 */
public abstract class AbstractManagementResource
        implements RequestRouter.Routes
    {
    // ----- RequestRouter.Routes methods -----------------------------------

    @Override
    public void addRoutes(RequestRouter router, String sPathRoot)
        {
        }

    // ----- AbstractManagementResource methods -----------------------------

    /**
     * Returns a {@link Map} deserialized from the json body of a request.
     *
     * @param request  the request with the body to deserialize
     *
     * @return  a {@link Map} deserialized from the json body of a request
     */
    protected Map getJsonBody(HttpRequest request)
        {
        MapJsonBodyHandler  jsonBodyHandler = ensureMapJsonBodyHandler();
        Map map             = request.getJsonBody(jsonBodyHandler::readMap);
        for (Map.Entry entry : map.entrySet())
            {
            Object oValue = entry.getValue();
            if (oValue instanceof Long)
                {
                long l = (Long) oValue;
                if (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE)
                    {
                    entry.setValue(((Number) oValue).intValue());
                    }
                }
            }

        return map;
        }

    /**
     * Ensure the {@link MapJsonBodyHandler} has been created that will be
     * used to serialize and deserialize json to and from {@link Map Maps}.
     *
     * @return the {@link MapJsonBodyHandler} used to serialize and deserialize
     *         json request and response bodies
     */
    protected MapJsonBodyHandler ensureMapJsonBodyHandler()
        {
        if (s_jsonBodyHandler == null)
            {
            s_jsonBodyHandler = MapJsonBodyHandler.ensureMapJsonBodyHandler();
            }
        return s_jsonBodyHandler;
        }

    /**
     * Update the attributes of an MBean, with the provided json entity
     *
     * @param request       the {@link HttpRequest}
     * @param entity        the json object which contains the keys to be updated
     * @param queryBuilder  the {@link QueryBuilder} to be used to generate MBean query
     *
     * @return the Response object
     */
    protected Response update(HttpRequest request, Map entity, QueryBuilder queryBuilder)
        {
        try
            {
            if (queryBuilder.toString().contains(MANAGEMENT_QUERY))
                {
                checkAttributeTypeConversion(entity, true);
                }
            else
                {
                checkAttributeTypeConversion(entity);
                }

            MBeanResponse responseEntity = new MBeanResponse(request);
            MBeanAccessor accessor = ensureBeanAccessor(request);

            if (!entity.isEmpty())
                {
                Map attrMap = entity.entrySet()
                        .stream()
                        .collect(Collectors.toMap(e -> fromRestName(e.getKey()), Map.Entry::getValue));

                Map> mapUpdatedMBeans = accessor.update(queryBuilder.build(), attrMap);

                if (mapUpdatedMBeans.isEmpty())
                    {
                    return Response.status(Response.Status.NOT_FOUND).build();
                    }

                for (Map.Entry> entry : mapUpdatedMBeans.entrySet())
                    {
                    String              sObjName      = entry.getKey();
                    Map mapAttributes = entry.getValue();

                    for (String sAttrKey : attrMap.keySet())
                        {
                        if (!mapAttributes.containsKey(sAttrKey))
                            {
                            responseEntity.addFailure(getRestName(sAttrKey),
                                    "Update attribute failed for MBean: " + sObjName);
                            }
                        }
                    }
                }
            return response(responseEntity.toJson());
            }
        catch (IllegalArgumentException iae)
            {
            Logger.info("Request precondition failure for updating an MBean with query " + queryBuilder +
                ". Failure is " + iae.getClass().getName() + " " + iae.getMessage());

            return Response.status(Response.Status.BAD_REQUEST)
                    .entity(Response.Status.BAD_REQUEST.getReasonPhrase() + '\n' + iae.getMessage())
                    .build();
            }
        catch (RuntimeMBeanException e)
            {
            if (isSecurityException(e.getTargetException()))
                {
                return Response.status(Response.Status.UNAUTHORIZED).build();
                }
            
            return createInternalServerError(queryBuilder, e);
            }
        catch (SecurityException e)
            {
            return Response.status(Response.Status.UNAUTHORIZED).build();
            }
        catch (Exception e)
            {
            return createInternalServerError(queryBuilder, e);
            }
        }

    /**
     * Create an internal server error {@link Response}.
     *
     * @param queryBuilder  the {@link QueryBuilder} to be used to generate MBean query
     * @param e {@link Exception} that caused the error
     * @return a new {@link Response}
     */
    private Response createInternalServerError(QueryBuilder queryBuilder, Exception e)
        {
        Logger.warn("Exception occurred while updating an MBean with query " + queryBuilder.toString(), e);
        // internal server error
        return Response.serverError().build();
        }

    /**
     * Calculate the response body required for a single MBean.
     *
     * @param request       the {@link HttpRequest}
     * @param queryBuilder  the {@link QueryBuilder} to be used to generate MBean query
     * @param asChildLinks  the child links to be added to the response
     *
     * @return the entity response for the MBean
     */
    protected EntityMBeanResponse getResponseEntityForMbean(HttpRequest  request,
                                                            QueryBuilder queryBuilder,
                                                            String...    asChildLinks)
        {
        return getResponseEntityForMbean(request, queryBuilder, getParentUri(request), getCurrentUri(request),
                                         getAttributesFilter(request), getLinksFilter(request), asChildLinks);
        }

    /**
     * Calculate the response body required for a single MBean.
     *
     * @param request       the {@link HttpRequest}
     * @param queryBuilder  the {@link QueryBuilder} to be used to generate MBean query
     * @param uriParent     the parent URI of the request, the parent URI is one level up
     *                      from the current resource
     * @param uriSelf       the self URI of the Mbean
     * @param mapQuery      the object query map, query map contains which child elements must be returned
     * @param asChildLinks  the child links to be added to the response
     *
     * @return the entity response for the MBean
     */
    protected EntityMBeanResponse getResponseEntityForMbean(HttpRequest         request,
                                                            QueryBuilder        queryBuilder,
                                                            URI                 uriParent,
                                                            URI                 uriSelf,
                                                            Map mapQuery,
                                                            String...           asChildLinks)
        {
        return getResponseEntityForMbean(request, queryBuilder, uriParent, uriSelf, getAttributesFilter(request, mapQuery),
                                         getLinksFilter(request, mapQuery), asChildLinks);
        }

    /**
     * Calculate the response body for a single MBean.
     *
     *
     * @param request           the {@link HttpRequest}
     * @param queryBuilder      the {@link QueryBuilder} to be used to generate MBean query
     * @param uriParent         the parent URI of the resource
     * @param uriSelf           the self URI of the Mbean
     * @param filterAttributes  the attributes filter
     * @param filterLinks       the links filter
     * @param asChildLinks      the child links to be added to the response
     *
     * @return the entity response for the MBean
     */
    protected EntityMBeanResponse getResponseEntityForMbean(HttpRequest    request,
                                                            QueryBuilder   queryBuilder,
                                                            URI            uriParent,
                                                            URI            uriSelf,
                                                            Filter filterAttributes,
                                                            Filter filterLinks,
                                                            String...      asChildLinks)
        {
        try
            {
            EntityMBeanResponse responseEntity = createResponse(request, uriParent, uriSelf, filterLinks);
            MBeanAccessor       accessor       = ensureBeanAccessor(request);

            Map> mapResponses = accessor.getAttributes(queryBuilder.build());

            if (!mapResponses.isEmpty())
                {
                Map.Entry> responseEntry = mapResponses.entrySet().iterator().next();
                responseEntity.setEntity(getMBeanAttributesMap(filterAttributes, responseEntry.getValue(),
                        responseEntry.getKey()));
                }
            else
                {
                return null;
                }

            if (asChildLinks != null)
                {
                Arrays.stream(asChildLinks).forEach(l -> responseEntity.addResourceLink(l, getSubUri(uriSelf, l)));
                }

            return responseEntity;
            }
        catch (Exception e)
            {
            Logger.warn("Exception occurred while getting response body for MBean with query "
                        + queryBuilder.build(), e);
            if (e instanceof HttpException)
                {
                throw (HttpException) e;
                }

            // internal server error, also do not propagate the error
            throw new HttpException();
            }
        }

    /**
     * Execute an MBean operation with the provided parameters.
     *
     *
     * @param request         the {@link HttpRequest}
     * @param queryBuilder    the {@link QueryBuilder} to be used to generate MBean query
     * @param sOperationName  the name of the operation
     * @param aoArguments     the arguments of the operation
     * @param asSignature     the signature for the operation
     *
     * @return the Response to be sent
     */
    protected Response executeMBeanOperation(HttpRequest  request,
                                             QueryBuilder queryBuilder,
                                             String       sOperationName,
                                             Object[]     aoArguments,
                                             String[]     asSignature)
        {
        try
            {
            MBeanAccessor accessor = ensureBeanAccessor(request);

            Map mapMBeans = accessor.invoke(queryBuilder.build(), sOperationName, aoArguments, asSignature);

            if (mapMBeans.isEmpty())
                {
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
                }
            }
        catch (RuntimeException e)
            {
            Logger.warn("Exception occurred while executing an Mbean operation on query "
                            + queryBuilder.build() + ", and operationName " + sOperationName, e);

            MBeanResponse response = new MBeanResponse(request);
            String        sCause   = "unknown, refer to log files for more information";

            // extract the original error message
            Throwable tCause = Base.getOriginalException(e);
            if (tCause != null)
                {
                sCause = Base.getDeepMessage(tCause, "\n");
                }

            response.addFailure(sOperationName + " failed, Cause=" + sCause);

            // if the root cause is a SecurityException then return 401
            if (isSecurityException(tCause))
                {
                return Response.status(Response.Status.UNAUTHORIZED).entity(response.toJson()).build();
                }

            // some other reason so return a 400
            return Response.status(Response.Status.BAD_REQUEST).entity(response.toJson()).build();
            }
        return response(new MBeanResponse(request).toJson());
        }

    /**
     * Execute an operation in an Mbean and return the response.
     *
     * @param request         the {@link HttpRequest}
     * @param queryBuilder    the {@link QueryBuilder} to be used to generate MBean query
     * @param sResponseKey    the key in the response map to which the result must be put
     * @param sOperationName  the operation name
     *
     * @return the response
     */
    protected EntityMBeanResponse getResponseFromMBeanOperation(HttpRequest  request,
                                                                QueryBuilder queryBuilder,
                                                                String       sResponseKey,
                                                                String       sOperationName)
        {
        return getResponseFromMBeanOperation(request, queryBuilder, sResponseKey, sOperationName,
                                             null, null);
        }

    /**
     * Execute an operation in an MBean and return the response.
     *
     * @param request         the {@link HttpRequest}
     * @param queryBuilder    the {@link QueryBuilder} to be used to generate MBean query
     * @param sResponseKey    the key in the response map to which the result must be put
     * @param sOperationName  the operation name
     * @param aoArguments     the arguments of the Mbean operations
     * @param asSignature     the signature of the MBean operation
     *
     * @return the response
     */
    protected EntityMBeanResponse getResponseFromMBeanOperation(HttpRequest   request,
                                                                QueryBuilder  queryBuilder,
                                                                String        sResponseKey,
                                                                String        sOperationName,
                                                                Object[]      aoArguments,
                                                                String[]      asSignature)
        {
        URI             uriParent        = getParentUri(request);
        URI             uriSelf          = getCurrentUri(request);
        Filter  filterLinks      = getLinksFilter(request);
        Filter  filterAttributes = getAttributesFilter(request);

        try
            {
            EntityMBeanResponse responseBody = createResponse(request, uriParent, uriSelf, filterLinks);
            MBeanAccessor       accessor     = ensureBeanAccessor(request);
            Map mapMBeans    =
                    accessor.invoke(queryBuilder.build(), sOperationName, aoArguments, asSignature);

            if (!mapMBeans.isEmpty())
                {
                // when we are doing MBean operations isn REST with sResponseKey set, then the operation
                // should typically happen on only one MBean. In any case, we return the result
                // of only one MBean
                Map.Entry entry       = mapMBeans.entrySet().iterator().next();
                Map       mapResponse = new LinkedHashMap<>();

                if (filterAttributes.evaluate(sResponseKey.toUpperCase()))
                    {
                    mapResponse.put(getRestName(sResponseKey), Converter.convert(entry.getValue()));
                    }

                responseBody.setEntity(mapResponse);
                }
            return responseBody;
            }
        catch (RuntimeException e)
            {
            Logger.warn("Exception occurred while executing an Mbean operation on query" + queryBuilder.toString()
                    + "and operationName " + sOperationName, e);

            EntityMBeanResponse responseBody = createResponse(request, uriParent, uriSelf, filterLinks);
            String              sCause       = "unknown, refer to log files for more information";

            // extract the original error message
            Throwable tCause = Base.getOriginalException(e);
            if (tCause != null)
                {
                sCause = Base.getDeepMessage(tCause, "\n");
                }

            // if the root cause is a SecurityException then return 401
            if (isSecurityException(tCause))
                {
                responseBody.setSecurityException(true);
                }

            responseBody.addFailure(sOperationName + " failed, Cause=" + sCause);
            return responseBody;
            }
        }

    /**
     * Generate a response for a collection query. There are cases wherein a list of MBeans needs
     * to be grouped based on a unique key, for example list of services, list of caches etc. In such cases
     * the MBeans are grouped with that unique key property and the response is generated using the child
     * resource class.
     *
     *
     * @param request             the {@link HttpRequest}
     * @param queryBuilder        the {@link QueryBuilder} to be used to generate MBean query
     * @param resource            the resource object to be used to generate response for a individual element
     * @param sUniqueKeyProperty  the unique key property to use, in case multiple objects needs to be
     *                            coalesced into one. For example, there can be multiple Service MBeans
     *                            for the same service.
     * @param mapQuery            the object query map, query map contains which child elements must be returned
     * @param uriParent           the parent URI
     * @param uriSelf             the self URI
     * @param uriCurrent          the current URI
     *
     * @return the response for the collection
     */
    protected EntityMBeanResponse getResponseBodyForMBeanCollection(HttpRequest                request,
                                                                    QueryBuilder               queryBuilder,
                                                                    AbstractManagementResource resource,
                                                                    String                     sUniqueKeyProperty,
                                                                    Map        mapQuery,
                                                                    URI                        uriParent,
                                                                    URI                        uriSelf,
                                                                    URI                        uriCurrent,
                                                                    Map        mapArguments)
        {
        try
            {
            Filter      filterLinks    = getLinksFilter(request, mapQuery);
            EntityMBeanResponse responseEntity = createResponse(request, uriParent, uriSelf, filterLinks);
            MBeanAccessor       accessor       = ensureBeanAccessor(request);
            Set         setObjectNames = accessor.queryKeys(queryBuilder.build());

            if (setObjectNames != null && !setObjectNames.isEmpty())
                {
                List> listChildEntities = new ArrayList<>();

                // this is the case where there is a unique property, and the response needs to be fetched from
                // a child resource. For example, while querying for list of services, there can be multiple
                // ServiceMBeans
                // but there is only a single service, similarly CacheMBean as well. the unique property in both
                // theses cases is the name of the service/cache

                Set setObjNames = convertToObjectNames(setObjectNames);

                Map> mapMBeanToName = setObjNames.stream()
                        .collect(Collectors.groupingBy(o -> getObjectNameKey(o, sUniqueKeyProperty)));

                for (Map.Entry> entry : mapMBeanToName.entrySet())
                    {
                    // propagate the argument map to the child resources after appending the unique key
                    Map mapChildResourceArgs = new HashMap<>();
                    if (mapArguments != null)
                        {
                        mapChildResourceArgs.putAll(mapArguments);
                        }

                    mapChildResourceArgs.put(sUniqueKeyProperty, entry.getKey());

                    EntityMBeanResponse response = resource.getQueryResult(request, uriSelf, uriCurrent, mapQuery, mapChildResourceArgs);
                    if (response != null)
                        {
                        listChildEntities.add(response.toJson());
                        }
                    }
                responseEntity.setEntities(listChildEntities);
                }
            else
                {
                return null;
                }

            return responseEntity;
            }
        catch (Exception e)
            {
            Logger.warn("Exception occurred while getting response for an MBean collection with query "
                        + queryBuilder.build().getQuery(), e);
            throw new HttpException();
            }
        }

    /**
     * Return true if the {@link Throwable} is a {@link SecurityException} or is a wrapped one.
     *
     * @param tCause  {@link Throwable} to inspect
     * @return true if the {@link Throwable} is a {@link SecurityException}
     */
    private boolean isSecurityException(Throwable tCause)
        {
        return tCause instanceof SecurityException ||
               (tCause instanceof RuntimeException && tCause.getCause() instanceof WrapperException &&
                ((WrapperException) tCause.getCause()).getRootCause()   instanceof SecurityException);
        }

    private static String getObjectNameKey(ObjectName objectName, String sKey)
        {
        return String.valueOf(objectName.getKeyProperty(sKey));
        }

    /**
     * Generate a response for a collection query. For each child MBean, the response is generated
     * for its attributes followed by querying the child resources.
     *
     *
     * @param request       the {@link HttpRequest}
     * @param queryBuilder  the {@link QueryBuilder} to be used to generate MBean query
     * @param resource      the resource object to be used to generate response for a individual element
     * @param mapQuery      the object query map, query map contains which child elements must be returned
     * @param mapArguments  the arguments to the child resource
     * @param uriParent     the parent URI
     * @param uriSelf       the self URI
     * @param uriCurrent    the current URI
     *
     * @return the response for the collection
     */
    protected EntityMBeanResponse getResponseBodyForMBeanCollection(HttpRequest                request,
                                                                    QueryBuilder               queryBuilder,
                                                                    AbstractManagementResource resource,
                                                                    Map        mapQuery,
                                                                    Map        mapArguments,
                                                                    URI                        uriParent,
                                                                    URI                        uriSelf,
                                                                    URI                        uriCurrent)
        {
        try
            {
            Filter                   filterLinks    = getLinksFilter(request, mapQuery);
            EntityMBeanResponse              responseEntity = createResponse(request, uriParent, uriSelf, filterLinks);
            MBeanAccessor                    accessor       = ensureBeanAccessor(request);
            Map> mapMBeans      = accessor.getAttributes(queryBuilder.build());

            if (mapMBeans != null && !mapMBeans.isEmpty())
                {
                List> listChildEntities = new ArrayList<>();
                Filter            filterAttributes  = getAttributesFilter(request, mapQuery);

                for (Map.Entry> entry: mapMBeans.entrySet())
                    {
                    String              sObjName = entry.getKey();
                    ObjectName          objName  = new ObjectName(sObjName);

                    // propagate the argument map to the child resources after appending the unique key
                    Map mapChildResourceArgs = new HashMap<>();
                    if (mapArguments != null)
                        {
                        mapChildResourceArgs.putAll(mapArguments);
                        }

                    mapChildResourceArgs.put(MEMBER_KEY, getMemberReference(objName));

                    EntityMBeanResponse response = resource.getQueryResult(request, uriSelf, uriCurrent, mapQuery, mapChildResourceArgs);

                    response.getEntity().putAll(getMBeanAttributesMap(
                            filterAttributes, entry.getValue(), entry.getKey()));

                    listChildEntities.add(response.toJson());
                    }

                responseEntity.setEntities(listChildEntities);
                }
            return responseEntity;
            }
        catch (Exception e)
            {
            Logger.warn("Exception occurred while getting response for an MBean collection with query " +
                    queryBuilder.build(), e);
            throw new HttpException();
            }
        }

    /**
     * Generate a response for a collection query. Examples of collection queries are
     * list of members in a cluster, list of services in a cluster etc.
     *
     *
     * @param request             the {@link HttpRequest}
     * @param queryBuilder        the {@link QueryBuilder} to be used to generate MBean query
     * @param sUniqueKeyProperty  the unique key property, which is used to create the self link for the MBean.
     *                            For example, while querying for the list of federation topologies, each topology MBean
     *                            response will have a self link, and the self link will be {parentUri}/{name}.
     *                            In this case, the unique key property is the name, which is the topology name.
     * @param mapQuery            the object query map, query map contains which child elements must be returned
     * @param uriParent           the parent URI
     * @param uriSelf             the current URI
     *
     * @return the response for the collection
     */
    protected EntityMBeanResponse getResponseBodyForMBeanCollection(HttpRequest         request,
                                                                    QueryBuilder        queryBuilder,
                                                                    String              sUniqueKeyProperty,
                                                                    Map mapQuery,
                                                                    URI                 uriParent,
                                                                    URI                 uriSelf)
        {
        try
            {
            Filter                   filterLinks    = getLinksFilter(request, mapQuery);
            EntityMBeanResponse              responseEntity = createResponse(request, uriParent, uriSelf, filterLinks);
            MBeanAccessor                    accessor       = ensureBeanAccessor(request);
            Map> mapMBeans      = accessor.getAttributes(queryBuilder.build());

            if (mapMBeans != null && !mapMBeans.isEmpty())
                {
                List> listChildEntities = new ArrayList<>();

                // this is the cache where there are no child resource required
                // we just need to send the response for a list of MBeans, for example
                // list of back cache members for a single cache in a member
                Filter filterAttributes = getAttributesFilter(request, mapQuery);

                for (Map.Entry> entry: mapMBeans.entrySet())
                    {
                    String              sObjName      = entry.getKey();
                    Map mapAttributes = entry.getValue();
                    ObjectName          objectName    = new ObjectName(entry.getKey());
                    URI                 uriSub        =
                            getSubUri(uriSelf, objectName.getKeyProperty(sUniqueKeyProperty));

                    EntityMBeanResponse responseEntityChild = createResponse(request, uriSelf, uriSub, filterLinks);

                    responseEntityChild.setEntity(getMBeanAttributesMap(filterAttributes, mapAttributes, sObjName));

                    listChildEntities.add(responseEntityChild.toJson());
                    }
                responseEntity.setEntities(listChildEntities);
                }

            return responseEntity;
            }
        catch (Exception e)
            {
            Logger.warn("Exception occurred while getting response for an MBean collection with query "
                        + queryBuilder.build(), e);
            throw new HttpException();
            }
        }

    /**
     * Generate a response for a collection query. Examples of collection queries are
     * list of members in a cluster, list of services in a cluster etc.
     *
     * @param request       the {@link HttpRequest}
     * @param queryBuilder  the {@link QueryBuilder} to be used to generate MBean query
     * @param mapQuery      the object query map, query map contains which child elements must be returned
     * @param uriParent     the parent URI
     * @param uriSelf       the current URI
     *
     * @return the response for the collection
     */
    protected EntityMBeanResponse getResponseBodyForMBeanCollection(HttpRequest         request,
                                                                    QueryBuilder        queryBuilder,
                                                                    Map mapQuery,
                                                                    URI                 uriParent,
                                                                    URI                 uriSelf)
        {
        try
            {
            Filter                   filterLinks    = getLinksFilter(request, mapQuery);
            EntityMBeanResponse              responseEntity = createResponse(request, uriParent, uriSelf, filterLinks);
            MBeanAccessor                    accessor       = ensureBeanAccessor(request);
            Map> mapMBeans      = accessor.getAttributes(queryBuilder.build());

            if (mapMBeans != null && !mapMBeans.isEmpty())
                {
                List> listChildEntities = new ArrayList<>();

                // this is the cache where there are no child resource required
                // we just need to send the response for a list of MBeans, for example
                // list of back cache members for a single cache in a member
                Filter filterAttributes = getAttributesFilter(request, mapQuery);

                for (Map.Entry> entry: mapMBeans.entrySet())
                    {
                    listChildEntities.add(getMBeanAttributesMap(filterAttributes, entry.getValue(), entry.getKey()));
                    }

                responseEntity.setEntities(listChildEntities);
                }
            return responseEntity;
            }
        catch (Exception e)
            {
            Logger.warn("Exception occurred while getting response for an MBean collection with query "
                        + queryBuilder.build(), e);
            throw new HttpException();
            }
        }

    /**
     * Generate a response containing only links. Useful in cases where a URL may not have any
     * responses, but can have child URL's.
     *
     *
     * @param request      the {@link HttpRequest}
     * @param uriParent    the parent URI
     * @param uriSelf      the self URI
     * @param filterLinks  the links filter
     * @param aChildLinks  the child links to be added
     *
     * @return the response
     */
    protected EntityMBeanResponse getLinksOnlyResponseBody(HttpRequest    request,
                                                           URI            uriParent,
                                                           URI            uriSelf,
                                                           Filter filterLinks,
                                                           String...      aChildLinks)
        {
        EntityMBeanResponse responseEntity = createResponse(request, uriParent, uriSelf, filterLinks);

        if (aChildLinks != null)
            {
            Arrays.stream(aChildLinks).forEach(l -> responseEntity.addResourceLink(l, getSubUri(uriSelf, l)));
            }

        return responseEntity;
        }

    /**
     * Generate a response containing only links. Useful in cases where a URL may not have any
     * responses, but can have child URL's.
     *
     * @param request      the {@link HttpRequest}
     * @param uriParent    the parent URI
     * @param uriSelf      the current URI
     * @param aChildLinks  the child links to be added
     *
     * @return the response
     */
    protected EntityMBeanResponse getLinksOnlyResponseBody(HttpRequest request, URI uriParent, URI uriSelf, String... aChildLinks)
        {
        return getLinksOnlyResponseBody(request, uriParent, uriSelf, getLinksFilter(request), aChildLinks);
        }


    protected Map getAggregatedMetrics(HttpRequest  request,
                                                       String       sLocator,
                                                       String       sAttribute,
                                                       String       sCollector,
                                                       QueryBuilder queryBuilder)
        {
        try
            {
            MBeanAccessor accessor = ensureBeanAccessor(request);
            return accessor.aggregate(queryBuilder.build(), sLocator, sAttribute, sCollector);
            }
        catch (RuntimeException e)
            {
            Response.Status status = Response.Status.SERVICE_UNAVAILABLE;
            for (Throwable t = e; t != null; t = t.getCause())
                {
                if (t instanceof IllegalArgumentException ||
                        t instanceof AttributeNotFoundException)
                    {
                    status = Response.Status.BAD_REQUEST;
                    }
                }
            // if the request was well formed the issue must be with the remote
            // MBeanServer; log an error
            if (status.equals(Response.Status.BAD_REQUEST))
                {
                throw new HttpException(status.getStatusCode(),
                        "HTTP " + status.getStatusCode() + ' ' + status.getReasonPhrase() + '\n' +
                                e.getMessage());
                }
            else
                {
                Logger.warn("Exception occurred while aggregating metrics with query "
                        + queryBuilder.build(), e);
                throw new HttpException();
                }
            }
        }

    /**
     * Get the response, if the request is a query. Queries are special in the fact that
     * they start from the root resource(Cluster), and takes in an filter map.
     *
     * @param  request       the {@link HttpRequest}
     * @param  uriParent     the parent URI
     * @param  uriCurrent    the current URI
     * @param  mapQuery      the object query map, query map contains which child elements must be returned
     * @param  mapArguments  the arguments to the child resource
     * @return the response for the query
     */
    protected EntityMBeanResponse getQueryResult(HttpRequest         request,
                                                 URI                 uriParent,
                                                 URI                 uriCurrent,
                                                 Map mapQuery,
                                                 Map mapArguments)
        {
        return null;
        }

    /**
     * For the provided child resource, add the response of the query request.
     *
     * @param request            the {@link HttpRequest}
     * @param resource           the child Resource class
     * @param sChildResourceKey  the string key of the child in the query
     * @param mapResponse        the response map, to which the child response must be added
     * @param mapQuery           the object query map, query map contains which child elements must be returned
     */
    @SuppressWarnings("unchecked")
    protected void addChildResourceQueryResult(HttpRequest                request,
                                               AbstractManagementResource resource,
                                               String                     sChildResourceKey,
                                               Map        mapResponse,
                                               Map        mapQuery,
                                               Map        mapArguments)
        {
        URI    uriParent        = getParentUri(request);
        URI    uriCurrent       = getCurrentUri(request);
        Object childQueryEntity = mapQuery.get(sChildResourceKey);
        if (childQueryEntity instanceof Map)
            {
            EntityMBeanResponse responseEntity
                    = resource.getQueryResult(request, uriParent, uriCurrent, (Map) childQueryEntity, mapArguments);
            // add the response only if there is an entity
            if (responseEntity != null)
                {
                mapResponse.put(sChildResourceKey, responseEntity.toJson());
                }
            }
        }

    /**
     * For the provided child MBean query, fetch the response and add to the parent JSON.
     * @param request       the {@link HttpRequest}
     * @param parentURI     the parent URI
     * @param currentURI    the current URI
     * @param sChildKey     the string key of the child in the query
     * @param queryBuilder  the child Mbean query builder
     * @param mapResponse   the response map, to which the child response must be added
     * @param mapQuery      the object query map, query map contains which child elements must be returned
     * @param childLinks    the child links
     */
    @SuppressWarnings("rawtypes")
    protected void addChildMbeanQueryResult(HttpRequest         request,
                                            URI                 parentURI,
                                            URI                 currentURI,
                                            String              sChildKey,
                                            QueryBuilder        queryBuilder,
                                            Map mapResponse,
                                            Map                 mapQuery,
                                            String...           childLinks)
        {
        Object oChildValue = mapQuery.get(sChildKey);
        if (oChildValue instanceof Map)
            {
            Map                 mapChildrenQuery = (Map) oChildValue;
            Filter      attributesFilter = getAttributesFilter(request, mapChildrenQuery);
            EntityMBeanResponse responseEntity   = getResponseEntityForMbean(request, queryBuilder, parentURI,
                    currentURI, attributesFilter, getLinksFilter(request, mapChildrenQuery), childLinks);

            if (responseEntity != null)
                {
                mapResponse.put(sChildKey, responseEntity.toJson());
                }
            }
        }

    /**
     * Add the aggregated metrics of the provided MBean type in the response.
     *
     * @param request      the {@link HttpRequest}
     * @param sRoleName    either a regex to be applied against node ids or a role name
     * @param sCollector   the collector to use instead of the default
     * @param mapResponse  the response map to which the metrics needs to be added.
     */
    protected void addAggregatedMetricsToResponseMap(HttpRequest         request,
                                                     String              sRoleName,
                                                     String              sCollector,
                                                     QueryBuilder        queryBuilder,
                                                     Map mapResponse)
        {
        Map mapAggregatedMetrics =
                getAggregatedMetrics(request, sRoleName, null, sCollector, queryBuilder);

        Filter filterAttributes = getAttributesFilter(request);

        for (Map.Entry entry : mapAggregatedMetrics.entrySet())
            {
            String sAttributeKey = entry.getKey();
            if (filterAttributes.evaluate(sAttributeKey.toUpperCase()))
                {
                mapResponse.put(getRestName(sAttributeKey), Converter.convert(entry.getValue()));
                }
            }
        }

    /**
     * The filter used against the domainPartition.
     *
     * @return the filter used against the domainPartition
     */
    protected Filter getDomainPartitionFilter()
        {
        return m_filterDomainPartition;
        }

    /**
     * Return the reference to be used to link to a Member.
     * 

* If the provided {@link ObjectName} has a key property {@link MBeanAccessor#MEMBER member}, return its * property value. Otherwise, return the {@link ObjectName} key property value for * {@link MBeanAccessor#NODE_ID nodeId}. * * @param objName the ObjectName of the MBean * * @return the member reference */ protected String getMemberReference(ObjectName objName) { String sMemberName = objName.getKeyProperty(MEMBER); if (sMemberName != null) { return sMemberName; } return objName.getKeyProperty(MBeanAccessor.NODE_ID); } /** * Return the value corresponding to the key {@link #CHILDREN} * * @param mapQuery the map which needs to be used * * @return the children value */ protected Object getChildrenQuery(Map mapQuery) { return mapQuery == null ? null : mapQuery.get(CHILDREN); } /** * Return a {@link Map} which contains the attributes of the provided MBean. * * @param filterAttributes the filter to be applied on the attributes * @param mapResponse the response map * @param sObjName the ObjectName of the MBean * * @return the {@link Map} containing the attributes of the MBean * * @throws Exception thrown in case of JMX exceptions */ protected Map getMBeanAttributesMap(Filter filterAttributes, Map mapResponse, String sObjName) throws Exception { Map mapAttributes = new LinkedHashMap<>(); for (Map.Entry entry : mapResponse.entrySet()) { String sAttrName = getRestName(entry.getKey()); if (filterAttributes.evaluate(sAttrName)) { mapAttributes.put(sAttrName, Converter.convert(entry.getValue())); } } for (Map.Entry entryKeyValue : new ObjectName(sObjName).getKeyPropertyList().entrySet()) { String sKey = getRestName(entryKeyValue.getKey()); if (filterAttributes.evaluate(sKey)) { // avoid clobbering existing MBean attribute when there is a ObjectName key property with same name. // examples include Service MBean Type attribute and PSOldGen MemoryPool MBean Type attribute // clashing with ObjectName key property type. mapAttributes.putIfAbsent(sKey, entryKeyValue.getValue()); } } return mapAttributes; } /** * Convert the entity map to an {@link AttributeList} * * @param mapEntity the input entity map * * @return the {@link AttributeList} */ protected AttributeList getAttributeList(Map mapEntity) { return new AttributeList(mapEntity.entrySet() .stream().map(e -> new Attribute(fromRestName(e.getKey()), e.getValue())) .collect(Collectors.toList())); } /** * Return an attributes filter based on the URI query parameters. * * @param request the {@link HttpRequest} * * @return the attributes filter */ protected Filter getAttributesFilter(HttpRequest request) { // MBean attributes are called "fields" in the REST language QueryParameters queryParameters = request.getQueryParameters(); String sIncludeFields = queryParameters.getFirst(INCLUDE_FIELDS); String sExcludeFields = queryParameters.getFirst(EXCLUDE_FIELDS); return getAttributesFilter(sIncludeFields, sExcludeFields); } /** * Return an attributes filter based on the provided include and exclude strings. * * @param sIncludeFields the comma separated list of included attributes * @param sExcludeFields the comma separated list of excluded attributes * * @return the attributes filter */ @SuppressWarnings("unchecked") protected Filter getAttributesFilter(String sIncludeFields, String sExcludeFields) { Filter filterAttributes = Filters.always(); if (sIncludeFields != null) { Set setIncludedFields = Arrays.stream(sIncludeFields.split(",")) .map(String::toUpperCase) .collect(Collectors.toSet()); filterAttributes = Filters.in(String::toUpperCase, setIncludedFields); } if (sExcludeFields != null) { Set setExcludedFields = Arrays.stream(sExcludeFields.split(",")) .map(String::toUpperCase) .collect(Collectors.toSet()); Filter filterExclude = Filters.not(Filters.in(String::toUpperCase, setExcludedFields)); filterAttributes = filterExclude.and(filterAttributes); } return filterAttributes; } /** * Return a links filter based on the URI query parameters. * * @param request the {@link HttpRequest} * * @return the links filter */ @SuppressWarnings("unchecked") protected Filter getLinksFilter(HttpRequest request) { QueryParameters queryParameters = request.getQueryParameters(); String sIncludeLinks = queryParameters.getFirst(INCLUDE_LINKS); String sExcludeLinks = queryParameters.getFirst(EXCLUDE_LINKS); Filter filterLinks = Filters.always(); if (sIncludeLinks != null) { Set setIncludedLinks = Arrays.stream(sIncludeLinks.split(",")) .collect(Collectors.toSet()); filterLinks = Filters.in(ValueExtractor.identity(), setIncludedLinks); } if (sExcludeLinks != null) { Set setExcludedLinks = Arrays.stream(sExcludeLinks.split(",")) .collect(Collectors.toSet()); Filter filterExclude = Filters.not(Filters.in(ValueExtractor.identity(), setExcludedLinks)); filterLinks = filterExclude.and(filterLinks); } return filterLinks; } /** * Return a fields filter, the filter parameters is taken from the query map if that is not null * else it is taken from the URI query parameters. * * @param request the {@link HttpRequest} * @param mapQuery the query map * * @return the fields filter */ @SuppressWarnings({"unchecked", "rawtypes"}) protected Filter getAttributesFilter(HttpRequest request, Map mapQuery) { if (mapQuery == null) { return getAttributesFilter(request); } List listIncludeFields = (List) mapQuery.get(INCLUDE_FIELDS); List listExcludeFields = (List) mapQuery.get(EXCLUDE_FIELDS); Filter filterAttributes = Filters.always(); if (listIncludeFields != null) { Set setIncludedFields = listIncludeFields.stream() .map(String::toUpperCase) .collect(Collectors.toSet()); filterAttributes = Filters.in(String::toUpperCase, setIncludedFields); } if (listExcludeFields != null) { Set setExcludedFields = listExcludeFields.stream() .map(String::toUpperCase) .collect(Collectors.toSet()); Filter filterExclude = Filters.not(Filters.in(String::toUpperCase, setExcludedFields)); filterAttributes = filterExclude.and(filterAttributes); } return filterAttributes; } /** * Return a links filter, the filter parameters is taken from the query map if that is not null * else it is taken from the URI query parameters. * * @param request the {@link HttpRequest} * @param mapQuery the query map * * @return the links filter */ @SuppressWarnings({"rawtypes", "unchecked"}) protected Filter getLinksFilter(HttpRequest request, Map mapQuery) { if (mapQuery == null) { return getLinksFilter(request); } List listIncludeLinks = (List) mapQuery.get(INCLUDE_LINKS); List listExcludeLinks = (List) mapQuery.get(EXCLUDE_LINKS); Filter filterLinks = Filters.always(); if (listIncludeLinks != null) { Set setIncludedLinks = new HashSet<>(listIncludeLinks); filterLinks = Filters.in(ValueExtractor.identity(), setIncludedLinks); } if (listExcludeLinks != null) { Set setExcludedLinks = listExcludeLinks.stream() .map(AbstractManagementResource::fromRestName) .collect(Collectors.toSet()); Filter filterExclude = Filters.not(Filters.in(ValueExtractor.identity(), setExcludedLinks)); filterLinks = filterExclude.and(filterLinks); } return filterLinks; } /** * Get the exclusion list, from the mapQuery, if not {@code null}, else from the * URI query parameter. * * @param request the {@link HttpRequest} * * @return the comma separated list of attributes which needs to be excluded */ protected String getExcludeList(HttpRequest request) { return getExcludeList(request, null); } /** * Get the exclusion list, from the mapQuery, if not {@code null}, else from the * URI query parameter. * * @param request the {@link HttpRequest} * @param mapQuery the Query map * * @return the comma separated list of attributes which needs to be excluded */ @SuppressWarnings({"rawtypes", "unchecked"}) protected String getExcludeList(HttpRequest request, Map mapQuery) { if (mapQuery == null) { return request.getQueryParameters().getFirst(EXCLUDE_FIELDS); } List listExcludeFields = (List) mapQuery.get(EXCLUDE_FIELDS); return listExcludeFields == null ? null : String.join(",", listExcludeFields); } /** * Create an entity response. * * @param request the {@link HttpRequest} * @param parentUri the parent URI which needs to be added to the response * @param selfUri the self URI which needs to be added to the response * @param linksFilter the filter which needs to be applied on the links * * @return the entity response */ protected EntityMBeanResponse createResponse(HttpRequest request, URI parentUri, URI selfUri, Filter linksFilter) { EntityMBeanResponse responseBody = new EntityMBeanResponse(request, linksFilter); responseBody.addParentResourceLink(parentUri); responseBody.addSelfResourceLinks(selfUri); return responseBody; } /** * Create a response from the provided entity response. This method will throw an exception * if there is no entity in the MBean response. * * @param responseEntity the response entity * * @return the {@link Response} object */ protected Response response(EntityMBeanResponse responseEntity) { if (responseEntity == null) { return Response.notFound().build(); } if (responseEntity.isSecurityException()) { return Response.status(Response.Status.UNAUTHORIZED).entity(responseEntity.toJson()).build(); } // check if there are failures, and if so, should be classified as bad request if (responseEntity.hasFailures()) { return Response.status(Response.Status.BAD_REQUEST).entity(responseEntity.toJson()).build(); } if (responseEntity.isEmpty()) { return Response.status(Response.Status.NOT_FOUND).build(); } return Response.ok(responseEntity.toJson()).build(); } /** * Set the filter to be applied against the domainPartition. * * @param filter a filter to apply against the domainPartition */ public void setDomainPartitionFilter(Filter filter) { m_filterDomainPartition = filter; } /** * Create an OK response with the provided map as entity. * * @param mapResponse the response entity * * @return the {@link Response} object */ protected Response response(Map mapResponse) { return Response.ok(mapResponse).build(); } /** * Check for any attribute that must always be converted to {@link Long}/{@link Integer}/{@link Float}. * * @param entity {@link Map} to check */ protected void checkAttributeTypeConversion(Map entity) { checkAttributeTypeConversion(entity, false); } /** * Check for any attribute that must always be converted to {@link Long}/{@link Integer}/{@link Float}. *

* The type of the {@code expiryDelay} attribute for {@code CacheMBean} is {@link Integer} but it * is {@link Long} for {@code ManagementMBean}, therefore, this code takes this into account. * * @param entity {@link Map} to check * @param fManagement a flag to indicate if the query type is Management * * @throws IllegalArgumentException if type conversion for attribute's value fails */ protected void checkAttributeTypeConversion(Map entity, boolean fManagement) { entity.replaceAll((k, v) -> { Class clzConvertTo = Object.class; try { if ((SET_LONG.contains(k) || (fManagement && k.compareToIgnoreCase("expiryDelay") == 0)) && !(v instanceof Long)) { clzConvertTo = Long.TYPE; return Long.valueOf(v.toString()); } else if (SET_INTEGER.contains(k) && !(v instanceof Integer)) { clzConvertTo = Integer.TYPE; return Integer.valueOf(v.toString()); } else if (SET_FLOAT.contains(k) && !(v instanceof Float)) { clzConvertTo = Float.TYPE; return Float.valueOf(v.toString()); } else { return v; } } catch (Exception e) { throw new IllegalArgumentException("invalid value for attribute " + k + "; failed type conversion to " + clzConvertTo.getName() + " due to " + e.getClass().getName() + " " + e.getMessage(), e); } }); } // ----- accessors ------------------------------------------------------ /** * The {@link #SERVICE_NAME service name parameter} from the URI path. * * @param request the {@link HttpRequest} * * @return the service name */ protected String getService(HttpRequest request) { return request.getPathParameters().getFirst(SERVICE_NAME); } /** * Return the parent URI of the request. * * @return the parent URI */ public URI getParentUri(HttpRequest request) { URI uri = request.getRequestURI(); String sRawPath = uri.getRawPath(); if (sRawPath.charAt(sRawPath.length() - 1) == '/') { sRawPath = sRawPath.substring(0, sRawPath.length() - 1); } StringBuilder sPath = new StringBuilder(); String[] asSegment = sRawPath.split("/"); for (int i = 0; i < asSegment.length - 1; i++) { if (i > 0) { sPath.append('/'); } sPath.append(asSegment[i]); } return replacePath(request.getBaseURI(), sPath.toString()); } /** * The URI of the current resource. * * @return the resource URI */ protected URI getCurrentUri(HttpRequest request) { URI uri = request.getRequestURI(); String sPath = uri.getRawPath(); if (sPath.endsWith("/")) { sPath = sPath.substring(0, sPath.length() - 1); } return uri.resolve(URI.create(sPath)); } /** * The MBean Domain name to be used in the resource. * * @return the MBean domain name */ protected String getMBeanDomainName() { return ensureMBeanDomainName(); } // ----- static helper methods ------------------------------------------ /** * Return the MBean domain name being used for Coherence MBeans. * * @return the MBean domain name being used for Coherence MBeans */ private static String ensureMBeanDomainName() { if (s_sMBeanDomainName == null) { synchronized (AbstractManagementResource.class) { if (s_sMBeanDomainName == null) { Registry registry = CacheFactory.getCluster().getManagement(); String sDomainName = registry.getDomainName(); s_sMBeanDomainName = sDomainName == null || sDomainName.isEmpty() ? "Coherence*" : sDomainName; } } } return s_sMBeanDomainName; } /** * Return a new URI that is this specified URI with the path replaced by the replacement path. * * @param uri the original URI * @param sPath the new path * * @return the new URI with the path replaced */ protected static URI replacePath(URI uri, String sPath) { // add any query from the parent String sQuery = uri.getRawQuery(); if (sQuery != null && sQuery.length() > 0) { sPath = sPath + "?" + sQuery; } // add any fragment from the parent String sFragment = uri.getRawFragment(); if (sFragment != null && sFragment.length() > 0) { sPath = sPath + "#" + sFragment; } // return the new URI return uri.resolve(URI.create(sPath)); } /** * Convert a name into a REST standards compatible name. * * @param sName the service name to be normalized * * @return the REST compatible name */ public static String getRestName(String sName) { // find the first set of upper case letters int count = 0; for (; count < sName.length(); count++) { if (!Character.isUpperCase(sName.charAt(count))) { break; } } if (count == sName.length()) { // all upper case - leave it alone return sName; } if (count == 0) { // doesn't start upper case - leave it alone return sName; } if (count == 1) { // first letter is upper case and next letter is lower case, so convert // first letter to lower case // for example RefreshTime must be returned as refreshTime return sName.substring(0, count).toLowerCase() + sName.substring(count); } // starts with an acronym - leave it alone return sName; } /** * Convert a name from a REST standards compatible name to attribute name. * * @param sName the service name to be normalized * * @return the REST compatible name */ public static String fromRestName(String sName) { // we are assuming here that any attribute which can be updated belongs to the standard // set of attributes which we converted in the getRestName method above // we need to have a better logic based on a cached set of MBeaninfo objects here // if we find more number of instances of attributes which starts with acronym etc return sName.substring(0, 1).toUpperCase() + sName.substring(1); } /** * Append the provided segments to the parent URI. * * @param uriParent the parent URI * @param asSegments the segments to be appended * * @return the resulting URI */ public static URI getSubUri(URI uriParent, String... asSegments) { try { StringBuilder builder = new StringBuilder(); builder.append(uriParent.getPath()); for (String segment : asSegments) { int cSlash = segment.indexOf('/'); if (cSlash == -1) { builder.append("/").append(segment); } else { for (String sPart : PATH_PATTERN.split(segment)) { builder.append("/").append(sPart); } } } String sEncoded = encodePath(builder.toString()); return uriParent.resolve(sEncoded); } catch (URISyntaxException e) { throw Exceptions.ensureRuntimeException(e); } } private static String encodePath(String sPath) throws URISyntaxException { // We cannot use the JDK URLEncoder as it encodes spaces as "+", which is wrong. // Instead we create a dummy URI, then use its raw path, which will be properly escaped return new URI("http", "localhost", sPath, null).getRawPath(); } /** * Convert the set string representations of {@link ObjectName}. * * @param setObjectNames the set of object names(string objects) * * @return the set of {@link ObjectName}s * * @throws MalformedObjectNameException thrown in case of malformed object name */ public static Set convertToObjectNames(Set setObjectNames) throws MalformedObjectNameException { Set setObjNames = new HashSet<>(); for (String sObjectName : setObjectNames) { setObjNames.add(new ObjectName(sObjectName)); } return setObjNames; } /** * Create a QueryBuilder, also set the common parameters in the builder. * * @param request the {@link HttpRequest} * * @return the QueryBuilder */ protected QueryBuilder createQueryBuilder(HttpRequest request) { String sCluster = getClusterName(request); return createQueryBuilder(sCluster); } /** * Create a QueryBuilder, also set the common parameters in the builder. * * @param sCluster the Coherence cluster name * * @return the QueryBuilder */ protected QueryBuilder createQueryBuilder(String sCluster) { String sDomain = getMBeanDomainName(); QueryBuilder queryBuilder = new QueryBuilder() .withMBeanDomainName(sDomain) .withCluster(sCluster); Filter filter = getDomainPartitionFilter(); if (filter != null) { queryBuilder.withFilter(DOMAIN_PARTITION, getDomainPartitionFilter()); } return queryBuilder; } /** * Create a health check QueryBuilder. * * @param request the {@link HttpRequest} * * @return the QueryBuilder */ protected QueryBuilder createHealthQueryBuilder(HttpRequest request) { String sSubType = request.getFirstPathParameter(SUB_TYPE); String sName = request.getFirstPathParameter(NAME); return createHealthQueryBuilder(request, sSubType, sName); } /** * Create a health check QueryBuilder. * * @param request the {@link HttpRequest} * @param sSubType an optional health check subtype * @param sName an optional health check name * * @return the QueryBuilder */ protected QueryBuilder createHealthQueryBuilder(HttpRequest request, String sSubType, String sName) { if (sSubType == null || sSubType.isEmpty()) { sSubType = "*"; } if (sName == null || sName.isEmpty()) { sName = "*"; } return createQueryBuilder(request).withBaseQuery(String.format(HEALTH_NAMED_QUERY, sSubType, sName)); } /** * Retruns the cluster name for the request. * * @param request the http request * * @return the cluster name for the request */ protected String getClusterName(HttpRequest request) { // first try the path parameter String sCluster = request.getFirstPathParameter(CLUSTER_NAME); if (sCluster == null || sCluster.isEmpty()) { // Not in the request path, try the resource registry sCluster = request.getResourceRegistry().getResource(String.class, CLUSTER_NAME); } if (sCluster == null || sCluster.isEmpty()) { // Not in the resource registry, if using Extended MBean names // get the actual cluster name, otherwise return null Cluster cluster = CacheFactory.getCluster(); Registry management = cluster.getManagement(); boolean fExtended = management.isExtendedMBeanName(); sCluster = fExtended ? cluster.getLocalMember().getClusterName() : null; } return sCluster; } /** * Returns the current {@link MBeanAccessor} for the request. *

* If the current {@link MBeanAccessor} has not been set, a new instance will be * created using the {@link MBeanServerProxy} from the request's resource registry * (or if that has not been set, from the {@link Cluster#getManagement()} cluster's * management registry}. * * @param request the current {@link HttpRequest} * * @return the current {@link MBeanAccessor} for the request */ protected MBeanAccessor ensureBeanAccessor(HttpRequest request) { MBeanAccessor accessor = m_accessor; if (accessor == null) { MBeanServerProxy proxy = request.getResourceRegistry().getResource(MBeanServerProxy.class); if (proxy == null) { proxy = CacheFactory.getCluster().getManagement().getMBeanServerProxy(); } accessor = m_accessor = new MBeanAccessor(proxy); } return accessor; } /** * Checks to see if a federated service and member is valid. * * @param request the {@link HttpRequest} * * @return true if the service name is a federated service and the member exists */ protected boolean isFederatedServiceMemberValid(HttpRequest request) { String sServiceName = request.getFirstPathParameter(SERVICE_NAME); String sMemberKey = request.getFirstPathParameter(MEMBER_KEY); Set setQueries = new HashSet<>(); setQueries.add(createQueryBuilder(request).withBaseQuery(FEDERATION_COORDINATOR_QUERY).withService(sServiceName)); setQueries.add(createQueryBuilder(request).withBaseQuery(SERVICE_MEMBERS_QUERY + sServiceName).withMember(sMemberKey)); // run both queries to ensure service is federated and the service members exist and fail fast for (QueryBuilder queryBuilder : setQueries) { EntityMBeanResponse response = getResponseEntityForMbean(request, queryBuilder, getParentUri(request), getCurrentUri(request), getAttributesFilter(request), getLinksFilter(request)); if (response == null || response.hasFailures() || response.isEmpty()) { return false; } } return true; } // ----- constants ------------------------------------------------------ /** * The query parameter used to filter attributes, the parameter value must be a subset of * attributes which needs to be included. */ public static final String INCLUDE_FIELDS = "fields"; /** * The query parameter used to filter links, the parameter value must be a subset of * links which needs to be included. */ public static final String INCLUDE_LINKS = "links"; /** * The query parameter used to filter attributes, the parameter value must be a subset of * attributes which needs to be excluded. */ public static final String EXCLUDE_FIELDS = "excludeFields"; /** * The query parameter used to filter links, the parameter value must be a subset of * links which needs to be excluded. */ public static final String EXCLUDE_LINKS = "excludeLinks"; /** * Constant used for json application type. */ public static final String MEDIA_TYPE_JSON = "application/json"; /** * Constant used for Swagger. */ public static final String MEDIA_TYPE_SWAGGER_JSON = "application/swagger+json"; /** * Swagger resource file name. */ public static final String SWAGGER_RESOURCE = "management-swagger.json"; /** * Constant used for applicable media types in the management REST interface. */ public static final String MEDIA_TYPES = MEDIA_TYPE_JSON; // ------------------------------ Mbean Query patterns ----------------------------------- /** * MBean query to filter out all the CacheMBean objects in the cluster. */ public static final String CACHES_QUERY = ":" + Registry.CACHE_TYPE; /** * MBean query to filter out all the CacheMBean objects of a particular cache. */ public static final String CACHE_QUERY = CACHES_QUERY + "," + Registry.KEY_NAME; /** * MBean query to filter out all the PagedTopicMBean objects in the cluster. */ public static final String TOPICS_QUERY = ":" + Registry.PAGED_TOPIC_TYPE; /** * MBean query to filter out all the PagedTopicMBean objects of a particular topic. */ public static final String TOPIC_QUERY = TOPICS_QUERY + "," + Registry.KEY_NAME; /** * MBean query to filter out all the TopicSubscriberMBean objects in the cluster. */ public static final String SUBSCRIBERS_QUERY = ":" + Registry.SUBSCRIBER_TYPE; /** * MBean query to filter out all the TopicSubscriberMBean objects of a particular topic. */ public static final String SUBSCRIBER_QUERY = SUBSCRIBERS_QUERY + ",id="; /** * MBean query to filter out all the TopicSubscriberMBean objects of a particular topic. */ public static final String TOPIC_SUBSCRIBERS_QUERY = SUBSCRIBERS_QUERY + "," + Registry.KEY_TOPIC; /** * MBean query to filter out all the TopicSubscriberMBean objects in the cluster. */ public static final String SUBSCRIBER_GROUPS_QUERY = ":" + Registry.SUBSCRIBER_GROUP_TYPE; /** * MBean query to filter out all the TopicSubscriberMBean objects of a particular topic. */ public static final String TOPIC_SUBSCRIBER_GROUPS_QUERY = SUBSCRIBER_GROUPS_QUERY + "," + Registry.KEY_TOPIC; /** * MBean query to filter out all the TopicSubscriberGroupsMBean objects of a particular topic. */ public static final String TOPIC_SUBSCRIBER_GROUP_QUERY = SUBSCRIBER_GROUPS_QUERY + "," + Registry.KEY_TOPIC + "%s," + Registry.KEY_NAME + "%s"; /** * MBean query to filter out all the CacheMBean objects of a particular cache and service. */ public static final String CACHE_MEMBERS_WITH_SERVICE_QUERY = CACHES_QUERY +"," + Registry.KEY_NAME; /** * MBean query to filter out all the NodeMBean objects. */ public static final String CLUSTER_MEMBERS_QUERY = ":" + Registry.NODE_TYPE; /** * MBean query to filter out all the ReporterMBean objects. */ public static final String REPORTER_MEMBERS_QUERY = ":" + Registry.REPORTER_TYPE; /** * MBean query to filter out all the Flash journal MBean objects. */ public static final String FLASH_JOURNAL_QUERY = ":" + Registry.JOURNAL_TYPE + "," + Registry.KEY_NAME + "FlashJournalRM"; /** * MBean query to filter out all the RAM journal MBean objects. */ public static final String RAM_JOURNAL_QUERY = ":" + Registry.JOURNAL_TYPE + "," + Registry.KEY_NAME + "RamJournalRM"; /** * MBean query to filter out all the Cluster MBeans. */ public static final String CLUSTER_QUERY = ":" + Registry.CLUSTER_TYPE; /** * MBean query to filter out all the Management MBeans. */ public static final String MANAGEMENT_QUERY = ":" + Registry.MANAGEMENT_TYPE; /** * MBean query to filter out all the PointToPoint MBeans. */ public static final String POINT_TO_POINT_QUERY = ":" + Registry.POINT_TO_POINT_TYPE; /** * MBean query to filter out all the ConnectionManager(Proxy) MBeans. */ public static final String CONNECTION_MANAGERS_QUERY = ":" + Registry.CONNECTION_MANAGER_TYPE; /** * MBean query to filter out all the ConnectionManager(Proxy) MBeans of a specific proxy service. */ public static final String CONNECTION_MANAGER_QUERY = CONNECTION_MANAGERS_QUERY + "," + Registry.KEY_NAME; /** * MBean query to filter out all the Connection(Proxy) MBeans. */ public static final String CONNECTIONS_QUERY = ":" + Registry.CONNECTION_TYPE + "," + Registry.KEY_NAME; /** * MBean query to filter out all the ServiceMBean of a specific service. */ public static final String SERVICE_MEMBERS_QUERY = ":" + Registry.SERVICE_TYPE + "," + Registry.KEY_NAME; /** * MBean query to filter out PartitionAssignment MBean of a specific service. */ public static final String PARTITION_ASSIGNMENT_QUERY = ":" + Registry.PARTITION_ASSIGNMENT_TYPE; /** * MBean query to filter out all ServiceMBean objects. */ public static final String SERVICES_QUERY = ":" + Registry.SERVICE_TYPE; /** * MBean query to filter out all ServiceMBean objects. */ public static final String FEDERATION_TYPE = ":" + Registry.FEDERATION_TYPE; /** * MBean query to filter out FederationManager MBean of a specific federated service. */ public static final String FEDERATION_COORDINATOR_QUERY = FEDERATION_TYPE + ",responsibility=Coordinator"; /** * MBean query to filter out Topology MBeans of a specific federated service and a specific participant. */ public static final String FEDERATION_TOPOLOGY_MEMBER_QUERY = FEDERATION_TYPE + "," + Registry.KEY_SUBTYPE_TYPE + "Topology," + Registry.KEY_NAME + "%s"; /** * MBean query to filter out Topology MBeans. */ public static final String FEDERATION_TOPOLOGIES_QUERY = FEDERATION_TYPE + ",subType=Topology"; /** * MBean query to filter out Destination MBeans of a specific federated service and a specific participant. */ public static final String DESTINATIONS_QUERY = FEDERATION_TYPE + ",subType=Destination," + Registry.KEY_NAME; /** * MBean query to filter out Destination MBeans of a specific federated service. */ public static final String DESTINATIONS_COLLECTION_QUERY= FEDERATION_TYPE + ",subType=Destination"; /** * MBean query to filter out Origin MBeans of a specific federated service. */ public static final String ORIGINS_COLLECTION_QUERY = FEDERATION_TYPE + ",subType=Origin"; /** * MBean query to filter out Origin MBeans of a specific federated service and specific participant. */ public static final String ORIGINS_QUERY = FEDERATION_TYPE + ",subType=Origin," + Registry.KEY_NAME; /** * MBean query to filter out PersistenceCoordinator MBean of a specific service. */ public static final String PERSISTENCE_CONTROLLER_QUERY = ":" + Registry.PERSISTENCE_SNAPSHOT_TYPE + ",responsibility=PersistenceCoordinator"; /** * MBean query to filter out platform(JVM) Memory MBean. */ public static final String PLATFORM_MEMORY_QUERY = ":type=Platform,Domain=java.lang,subType=Memory"; /** * MBean query to filter out platform(JVM) MemoryPool MBean(Compressed Class Space). */ public static final String COMPRESSED_CLASS_SPACE_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=Compressed Class Space"; /** * MBean query to filter out platform(JVM) MemoryPool MBean(Metaspace). */ public static final String META_SPACE_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=Metaspace"; /** * MBean query to filter out platform(JVM) PS GarbageCollector MBean(PS Mark sweep). */ public static final String PS_MARK_SWEEP_QUERY = ":type=Platform,Domain=java.lang,subType=GarbageCollector,name=PS MarkSweep"; /** * MBean query to filter out platform(JVM) PS GarbageCollector MBean(PS Scavenge). */ public static final String PS_SCAVENGE_QUERY = ":type=Platform,Domain=java.lang,subType=GarbageCollector,name=PS Scavenge"; /** * MBean query to filter out platform(JVM) PS MemoryPool MBean(PS Old Gen). */ public static final String PS_OLDGEN_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=PS Old Gen"; /** * MBean query to filter out platform(JVM) PS MemoryPool MBean(Code Cache). */ public static final String CODECACHE_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=Code Cache"; /** * MBean query to filter out platform(JVM) PS MemoryPool MBean(PS Eden Space). */ public static final String PS_EDEN_SPACE_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=PS Eden Space"; /** * MBean query to filter out platform(JVM) PS MemoryPool MBean(PS Survivor Space). */ public static final String PS_SURVIVOR_SPACE_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=PS Survivor Space"; /** * MBean query to filter out platform(JVM) OperatingSystem MBean. */ public static final String OS_QUERY = ":type=Platform,Domain=java.lang,subType=OperatingSystem"; /** * MBean query to filter out platform(JVM) Runtime MBean. */ public static final String RUNTIME_QUERY = ":type=Platform,Domain=java.lang,subType=Runtime"; /** * MBean query to filter out platform(JVM) G1 GarbageCollector MBean(G1 Old Generation). */ public static final String G1_OLD_GENERATION_QUERY = ":type=Platform,Domain=java.lang,subType=GarbageCollector,name=G1 Old Generation"; /** * MBean query to filter out platform(JVM) G1 GarbageCollector MBean(G1 Young Generation). */ public static final String G1_YOUNG_GENERATION_QUERY = ":type=Platform,Domain=java.lang,subType=GarbageCollector,name=G1 Young Generation"; /** * MBean query to filter out platform(JVM) G1 MemoryPool MBean(G1 Eden Space). */ public static final String G1_EDEN_SPACE_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=G1 Eden Space"; /** * MBean query to filter out platform(JVM) G1 MemoryPool MBean(G1 Old Gen). */ public static final String G1_OLDGEN_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=G1 Old Gen"; /** * MBean query to filter out platform(JVM) G1 MemoryPool MBean(G1 Survivor Space). */ public static final String G1_SURVIVOR_SPACE_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=G1 Survivor Space"; /** * MBean query to filter out platform(JVM) G1 MemoryPool MBean(CodeHeap 'non-nmethods'). */ public static final String G1_CODEHEAP_NON_NMETHODS_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=CodeHeap 'non-nmethods'"; /** * MBean query to filter out platform(JVM) G1 MemoryPool MBean(CodeHeap 'profiled nmethods'). */ public static final String G1_CODEHEAP_PROFILED_NMETHODS_QUERY = ":type=Platform,Domain=java.lang,subType=MemoryPool,name=CodeHeap 'profiled nmethods'"; /** * MBean query to filter out platform(JVM) G1 MemoryManager MBean(CodeCacheManager). */ public static final String G1_CODECACHE_MANAGER = ":type=Platform,Domain=java.lang,subType=MemoryManager,name=CodeCacheManager"; /** * MBean query to filter out platform(JVM) G1 MemoryManager MBean(Metaspace Manager). */ public static final String G1_METASPACE_MANAGER = ":type=Platform,Domain=java.lang,subType=MemoryManager,name=Metaspace Manager"; /** * MBean query to filter out CoherenceAdapter(HotCache) MBeans. */ public static final String HOTCACHE_MEMBERS_QUERY = ":type=CoherenceAdapter"; /** * MBean query to filter out HttpSessionManager(CWEb) MBeans. The * before the HttpSessionManager is to filter * out 2 kinds of MBeans, HttpSessionManager and WeblogicHttpSessionManager MBeans. */ public static final String CWEB_APPLICATIONS_QUERY = ":type=*HttpSessionManager"; /** * MBean query to filter out HttpSessionManager(CWEb) MBeans of a particular application. * The * before the HttpSessionManager is to filter out 2 kinds of MBeans, HttpSessionManager * and WeblogicHttpSessionManager MBeans. */ public static final String CWEB_APPLICATION_QUERY = ":type=*HttpSessionManager,appId="; /** * MBean query to filter out StorageManager MBean of a specific cache and service, running on a specific node. */ public static final String STORAGE_MANAGERS_QUERY = ":type=StorageManager,cache=%s"; /** * MBean query to filter out StorageManager MBean of a specific cache and service, running on a specific node. */ public static final String STORAGE_MANAGER_QUERY = ":type=StorageManager,cache=%s,service=%s,nodeId=%s"; /** * MBean query to filter out all the ExecutorMBean objects. * * @since 21.12 */ public static final String EXECUTORS_QUERY = ":" + Registry.EXECUTOR_TYPE; /** * MBean query to filter out Executor MBeans of a particular name. * * @since 21.12 */ public static final String EXECUTOR_QUERY = EXECUTORS_QUERY + "," + Registry.KEY_NAME; /** * MBean query to filter out all the Health MBeans. */ public static final String HEALTH_QUERY = ":" + Registry.HEALTH_TYPE; /** * MBean query to filter out all the Health MBeans. */ public static final String HEALTH_NAMED_QUERY = ":" + HealthCheckWrapperMBean.MBEAN_NAME_PATTERN; // ------------------------------ Mbean Query patterns ends --------------------------------- // ------------------------------ Path param constants -------------------------------------- public static final String CLUSTER_NAME = "clusterName"; public static final String SERVICE_NAME = "serviceName"; public static final String CACHE_NAME = "cacheName"; public static final String MEMBER_KEY = "memberKey"; public static final String VERSION = "versionName"; public static final String PARTICIPANT_NAME = "participantName"; public static final String TOPOLOGY_NAME = "topologyName"; public static final String OPERATION_NAME = "operationName"; public static final String PLATFORM_MBEAN = "platformMBean"; public static final String APPLICATION_ID = "applicationId"; public static final String DOMAIN_PARTITION = "domainPartition"; public static final String TOPOLOGIES = "topologies"; public static final String SNAPSHOT_NAME = "snapshotName"; public static final String JFR_CMD = "jfrCmd"; public static final String TOPIC_NAME = "topicName"; public static final String SUBSCRIBER_GROUP_NAME = "subscriberGroupName"; // ------------------------------ Path param constants ends -------------------------------------- // ------------------------------ URL constants -------------------------------------------------- public static final String METADATA_CATALOG = "metadata-catalog"; public static final String SERVICES = "services"; public static final String MEMBERS = "members"; public static final String REPORTERS = "reporters"; public static final String CACHES = "caches"; public static final String MANAGEMENT = "management"; public static final String SHUTDOWN = "shutdown"; public static final String CLUSTER_STATE = "logClusterState"; public static final String MEMBER_STATE = "logMemberState"; public static final String CLUSTER = "cluster"; public static final String SEARCH = "search"; public static final String STORAGE = "storage"; public static final String JOURNAL = "journal"; public static final String JOURNAL_TYPE = "journalType"; public static final String NETWORK_STATS = "networkStats"; public static final String VERBOSE = "verbose"; public static final String HOTCACHE = "hotcache"; public static final String WEB_APPS = "webApplications"; public static final String PERSISTENCE = "persistence"; public static final String PROXY = "proxy"; public static final String PARTICIPANTS = "participants"; public static final String STATISTICS = "statistics"; public static final String INCOMING = "incoming"; public static final String OUTGOING = "outgoing"; public static final String EXECUTORS = "executors"; public static final String STATE = "state"; public static final String ENVIRONMENT = "environment"; public static final String HEALTH = "health"; public static final String TOPICS = "topics"; public static final String SUBSCRIBERS = "subscribers"; public static final String SUBSCRIBER_GROUPS = "subscriberGroups"; public static final String SUBSCRIBER_GROUPS_LCASE = "subscribergroups"; public static final String CHANNELS = "channels"; // ------------------------------ URL constants ends --------------------------------------------- // ------------------------------ Misc constants ------------------------------------------------- public static final String LOADER = "loader"; public static final String MEMBER = "member"; public static final String CONNECTIONS = "connections"; public static final String ROLE_NAME = "role"; public static final String COLLECTOR = "collector"; public static final String PLATFORM = "platform"; public static final String RAM_JOURNAL_TYPE = "ram"; public static final String FLASH_JOURNAL_TYPE = "flash"; public static final String PARTITION = "partition"; public static final String FEDERATION = "federation"; public static final String RESET_STATS = "resetStatistics"; public static final String CHILDREN = "children"; public static final String NAME = "name"; public static final String TYPE = "type"; public static final String NODE_ID = "nodeId"; public static final String SERVICE = "service"; public static final String SUB_TYPE = "subType"; public static final String TIER_BACK = "back"; public static final String TIER = "tier"; public static final String OPTIONS = "options"; public static final String DOMAIN_NAME = "domainName"; public static final String DOMAIN_FILTER = "domainPartitionFilter"; public static final String SUBSCRIBER_ID = "id"; /** * Map of URL to platform Mbean query. */ public static final Map MAP_PLATFORM_URL_TO_MBEAN_QUERY = Collections.unmodifiableMap(new HashMap() {{ put("memory", PLATFORM_MEMORY_QUERY); put("metaSpace", META_SPACE_QUERY); put("compressedClassSpace", COMPRESSED_CLASS_SPACE_QUERY); put("operatingSystem", OS_QUERY); put("runtime", RUNTIME_QUERY); }}); /** * Map of URL to platform PS GC Mbean query. */ public static final Map MAP_PLATFORM_PS_URL_TO_MBEAN_QUERY = Collections.unmodifiableMap(new HashMap() {{ put("psMarkSweep", PS_MARK_SWEEP_QUERY); put("psScavenge", PS_SCAVENGE_QUERY); put("psOldGen", PS_OLDGEN_QUERY); put("psEdenSpace", PS_EDEN_SPACE_QUERY); put("psSurvivorSpace", PS_SURVIVOR_SPACE_QUERY); put("codeCache", CODECACHE_QUERY); }}); /** * Map of URL to platform G1 GC Mbean query. */ public static final Map MAP_PLATFORM_G1_URL_TO_MBEAN_QUERY = Collections.unmodifiableMap(new HashMap() {{ put("g1EdenSpace", G1_EDEN_SPACE_QUERY); put("g1OldGen", G1_OLDGEN_QUERY); put("g1OldGeneration", G1_OLD_GENERATION_QUERY); put("g1SurvivorSpace", G1_SURVIVOR_SPACE_QUERY); put("g1YoungGeneration", G1_YOUNG_GENERATION_QUERY); put("g1CodeHeapNonNMethods", G1_CODEHEAP_NON_NMETHODS_QUERY); put("g1CodeHeapProfiledNMethods", G1_CODEHEAP_PROFILED_NMETHODS_QUERY); put("g1CodeCacheManager", G1_CODECACHE_MANAGER); put("g1MetaSpaceManager", G1_METASPACE_MANAGER); }}); /** * Map of journal type fo MBean query. */ public static final Map MAP_JOURNAL_URL_TO_MBEAN_QUERY = Collections.unmodifiableMap(new HashMap() {{ put("flash", FLASH_JOURNAL_QUERY); put("ram", RAM_JOURNAL_QUERY); }}); /** * Set of attributes to be converted to Long. */ private static final Set SET_LONG = new HashSet<>(Arrays.asList( "intervalSeconds", "currentBatch", "taskHungThresholdMillis", "maxQueryThresholdMillis", "transportRetainedBytes", "requestTimeoutMillis", "taskTimeoutMillis")); /** * Set of attributes to be converted to Integer. */ private static final Set SET_INTEGER = new HashSet<>(Collections.singletonList("expiryDelay")); /** * Set of attributes to be converted to Float. */ private static final Set SET_FLOAT = new HashSet<>(Collections.singletonList("tracingSamplingRatio")); /** * Cached pattern for splitting request paths. */ private static final Pattern PATH_PATTERN = Pattern.compile("/"); /** * The json serializer. */ private static MapJsonBodyHandler s_jsonBodyHandler; // ----- data members --------------------------------------------------- /** * The filter used against the domainPartition. */ private Filter m_filterDomainPartition; /** * The domain MBean name to be used. */ private static volatile String s_sMBeanDomainName = null; /** * The {@link MBeanAccessor} to use to access MBean information. */ protected MBeanAccessor m_accessor; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy