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

com.tangosol.coherence.management.internal.resources.ClusterResource Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2023, 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.coherence.management.internal.resources;

import com.tangosol.coherence.management.internal.EntityMBeanResponse;

import com.tangosol.net.CacheFactory;

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

import com.tangosol.util.Resources;

import java.io.IOException;

import java.net.URI;
import java.net.URL;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

import javax.ws.rs.QueryParam;

import javax.ws.rs.WebApplicationException;

import javax.ws.rs.core.Response;

import static com.tangosol.coherence.management.internal.resources.ClusterMemberResource.DIAGNOSTIC_CMD;

/**
 * Handles management API requests for a Coherence cluster level MBeans.
 *
 * @author sr 2017.08.21
 * @since 12.2.1.4.0
 */
public class ClusterResource
        extends AbstractManagementResource
    {
    // ----- constructors ---------------------------------------------------

    /**
     * Construct a ClusterResource.
     *
     * @param resource  the {@link AbstractManagementResource} to be used to initialize the context
     */
    public ClusterResource(AbstractManagementResource resource)
        {
        super(resource);
        }

    // ----- GET API --------------------------------------------------------

    /**
     * Return the swagger document for the Management Resource.
     *
     * @return the response object
     */
    @GET
    @Produces(MEDIA_TYPES)
    @Consumes({MEDIA_TYPES, MEDIA_TYPE_SWAGGER_JSON})
    @Path(METADATA_CATALOG)
    public Response getMetadataCatalog()
        {
        URL url = Resources.findFileOrResource(SWAGGER_RESOURCE, this.getClass().getClassLoader());
        try
            {
            return url == null
                       ? Response.status(Response.Status.NOT_FOUND).build()
                       : Response.ok(url.openStream()).build();
            }
        catch (IOException e)
            {
            CacheFactory.log("Exception occurred while returning Swagger resource " + SWAGGER_RESOURCE
                              + "." + e.getMessage() + "\n" + CacheFactory.getStackTrace(e), CacheFactory.LOG_ERR);
            throw new WebApplicationException();
            }
        }

    /**
     * Return the attributes of a ClusterMBean.
     *
     * @return the response object
     */
    @GET
    @Produces(MEDIA_TYPES)
    public Response get()
        {
        return response(getResponseEntityForMbean(getQuery(), CHILD_LINKS));
        }

    /**
     * Return the attributes of a ManagementMBean.
     *
     * @return the response object
     */
    @GET
    @Produces(MEDIA_TYPES)
    @Path(MANAGEMENT)
    public Response getManagement()
        {
        return response(getResponseEntityForMbean(getManagementQuery()));
        }

    /**
     * Return the response to a "journal" link for a cluster.
     *
     * @return the response object
     */
    @GET
    @Produces(MEDIA_TYPES)
    @Path("journal")
    public Response getJournalResponse()
        {
        return response(getLinksOnlyResponseBody(getParentUri(), getCurrentUri(), "ram", "flash").toJson());
        }


    /**
     * Return aggregated metrics of a platform(JVM) MBean across cluster members.
     *
     * @param sPlatformMBeanType  the JVM MBean type
     * @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*
     *
     * @return the response object
     */
    @GET
    @Produces(MEDIA_TYPES)
    @Path(PLATFORM + "/{" + PLATFORM_MBEAN + "}")
    public Response getPlatformResponse(@PathParam(PLATFORM_MBEAN) String sPlatformMBeanType,
                                        @QueryParam(ROLE_NAME)     String sRoleName,
                                        @QueryParam(COLLECTOR)     String sCollector)
        {
        String sBaseQuery = MAP_PLATFORM_URL_TO_MBEAN_QUERY.get(sPlatformMBeanType);

        if (sBaseQuery == null)
            {
            sBaseQuery = MAP_PLATFORM_PS_URL_TO_MBEAN_QUERY.get(sPlatformMBeanType);
            if (sBaseQuery == null)
                {
                sBaseQuery = MAP_PLATFORM_G1_URL_TO_MBEAN_QUERY.get(sPlatformMBeanType);
                if (sBaseQuery == null)
                    {
                    return Response.status(Response.Status.NOT_FOUND).build();
                    }
                }
            }

        QueryBuilder        bldrQuery = createQueryBuilder().withBaseQuery(sBaseQuery);
        EntityMBeanResponse response  = getLinksOnlyResponseBody(getParentUri(), getCurrentUri());

        Map responseMap = response.toJson();

        addAggregatedMetricsToResponseMap(sRoleName, sCollector, bldrQuery, responseMap);

        return response(responseMap);
        }

    /**
     * Get Coherence Cluster Configuration
     *
     * @param request  the {@link HttpRequest}
     *
     * @return the response object
     *
     * @since 14.1.1.0
     */
    @GET
    @Produces(MEDIA_TYPE_XML)
    @Path(GET_CLUSTER_CONFIG)
    public Response getClusterConfig()
        {
        return executeMBeanOperation(getQuery(), GET_CLUSTER_CONFIG, null, null);
        }

    /**
     * Get the cluster description.
     *
     * @return the response object
     *
     * @since 14.1.1.15
     */
    @GET
    @Produces(MEDIA_TYPES)
    @Path(DESCRIPTION)
    public Response getClusterDescription()
        {
        return response(getResponseFromMBeanOperation(getQuery(), "description", "getClusterDescription"));
        }

    // ----- POST API (Operations) ------------------------------------------

    /**
     * Call "shutdown" operation on ClusterMBean.
     *
     * @return the response object
     */
    @POST
    @Produces(MEDIA_TYPES)
    @Path("shutdown")
    public Response shutdownCluster()
        {
        return executeMBeanOperation(getQuery(), "shutdown", null, null);
        }

    /**
     * Call "logClusterState" operation on ClusterMBean.
     *
     * @param mapParameters  the method parameters map
     *
     * @return the response object
     */
    @POST
    @Produces(MEDIA_TYPES)
    @Consumes(MEDIA_TYPES)
    @Path("logClusterState")
    public Response logClusterState(Map mapParameters)
        {
        Object oRole = mapParameters == null ? null : mapParameters.get(ROLE);
        return executeMBeanOperation(getQuery(), "logClusterState",
                new Object[]{oRole}, new String[] {String.class.getName()});
        }

    /**
     * Call "dumpClusterHeap" operation on ClusterMBean.
     *
     * @param mapParameters  the method parameters map
     *
     * @return the response object
     */
    @POST
    @Produces(MEDIA_TYPES)
    @Consumes(MEDIA_TYPES)
    @Path(DUMP_CLUSTER_HEAP)
    public Response dumpClusterHeap(Map mapParameters)
        {
        Object oRole = mapParameters == null ? null : mapParameters.get(ROLE);
        return executeMBeanOperation(getQuery(), DUMP_CLUSTER_HEAP,
                new Object[]{oRole}, new String[] {String.class.getName()});
        }

    /**
     * Call the {@value CONFIGURE_TRACING} operation on ClusterMBean.
     * 

* This call expects two parameters, {@value ROLE} and {@value TRACING_RATIO}. {@value ROLE} allows enabling * tracing on members matching the specified role. If {@value ROLE} is null or a zero-length string, * {@value TRACING_RATIO} will be applied to all members of the cluster. {@value TRACING_RATIO} specifies * the ratio of tracing spans that will be captured. A value of {@code -1} disables tracing. A value of * {@code 0} means Coherence will not initiate spans unless an active span is already present. * A value between {@code 0} (exclusively) and {@code 1.0} (inclusively) represents the percentage of tracing * spans that will be captured. * * @param mapParameters the method parameters map * * @return the response object * * @since 14.1.1.0 */ @POST @Produces(MEDIA_TYPES) @Consumes(MEDIA_TYPES) @Path(CONFIGURE_TRACING) public Response configureTracing(Map mapParameters) { Object oRole = mapParameters == null ? null : mapParameters.get(ROLE); Float oRatio = mapParameters == null ? -1.0f : Float.parseFloat(mapParameters.get(TRACING_RATIO).toString()); return executeMBeanOperation(getQuery(), CONFIGURE_TRACING, new Object[]{oRole, oRatio}, new String[] {String.class.getName(), Float.class.getName()}); } // ----- POST API(Update) ----------------------------------------------- /** * Update a ManagementMBean with the parameters present in the input entity map. * * @param mapParameters the method parameters map * * @return the response object */ @POST @Produces(MEDIA_TYPES) @Consumes(MEDIA_TYPES) @Path(MANAGEMENT) public Response updateJMXManagement(Map mapParameters) { return update(mapParameters, getManagementQuery()); } // ----- POST API(Search) ----------------------------------------------- @POST @Produces(MEDIA_TYPES) @Path(SEARCH) public Response search(Map mapQuery) { return response(getSearchResults(mapQuery, getParentUri(), getCurrentUri())); } // ----- Child Resources ------------------------------------------------ /** * Sub resource for cluster members. * * @return the cluster members sub resource */ @Path(MEMBERS) public Object getMembersResource() { return new ClusterMembersResource(this); } /** * Sub resource for services. * * @return the services sub resource */ @Path(SERVICES) public Object getServicesResource() { return new ServicesResource(this); } /** * Sub resource for caches. * * @return the caches sub resource */ @Path(CACHES) public Object getCachesResource() { return new CachesResource(this); } /** * Sub resource for a journal type. * * @return the journal sub resource */ @Path(JOURNAL + "/{" + JOURNAL_TYPE + ":ram|flash}") public Object getJournalResource() { return new JournalResource(this); } /** * Sub resource for C*W applications. * * @return the C*W applications sub resource */ @Path(WEB_APPS) public Object getWebAppsResource() { return new CWebResource(this); } /** * Sub resource for reporters. * * @return the reporters sub resource */ @Path(REPORTERS) public Object getReportersResource() { return new ReportersResource(this); } /** * Sub resource for storage. * * @return the storage sub resource */ @Path(STORAGE) public Object getStorageManagersResource() { return new StorageManagersResource(this); } /** * Call "diagnostic-cmd/jfrCmd" to perform JFR operation on ClusterMBean. * * Valid commands are jfrStart, jfrStop, jfrDump, and jfrCheck. See jcmd JFR * command for valid options. E.g. * jfrStart?options=name=myJfr,duration=3s,filename=/tmp/myRecording.jfr * * @param sCmd the JFR command * @param sOptions the comma separated JFR options * @param sRole the Coherence role name * * @return the response object */ @POST @Produces(MEDIA_TYPES) @Consumes(MEDIA_TYPES) @Path(DIAGNOSTIC_CMD + "/{" + JFR_CMD + "}") public Response diagnosticCmd(@PathParam(JFR_CMD) String sCmd, @QueryParam(OPTIONS) String sOptions, @QueryParam(ROLE_NAME) String sRole) { // execute the role based cluster wide JFR operation and return // the result message from the operation return response(getResponseFromMBeanOperation(getQuery(), "status", "flightRecording", new Object[]{sRole, sCmd, sOptions}, new String[]{String.class.getName(), String.class.getName(), String.class.getName()})); } // ----- ClusterResource methods ---------------------------------------- /** * The response for a Coherence ClusterMBean. * * @param uriParent the parent URI * @param sClusterName the cluster name * * @return response for a Coherence ClusterMBean */ public Map getClusterResponseMap(URI uriParent, String sClusterName) { EntityMBeanResponse response = getResponseEntityForMbean(getQuery(), uriParent, getSubUri(uriParent, sClusterName), null, CHILD_LINKS); return response != null ? response.toJson() : new LinkedHashMap<>(); } /** * Return the search results for a Coherence Cluster. * * @param mapQuery the Query map * @param uriParent the parent URI of the current resource * @param uriCurrent the current URI of the resource * * @return the cluster search results */ @SuppressWarnings("CollectionAddAllCanBeReplacedWithConstructor") public Map getSearchResults(Map mapQuery, URI uriParent, URI uriCurrent) { Map mapResponse = new LinkedHashMap<>(); EntityMBeanResponse response = getResponseEntityForMbean(getQuery(), uriParent, uriCurrent, mapQuery); mapResponse.putAll(response.toJson()); Object oChildren = getChildrenQuery(mapQuery); if (oChildren instanceof Map) { Map mapChildrenQuery = (Map) oChildren; addChildMbeanQueryResult(MANAGEMENT, getManagementQuery(), mapResponse, mapChildrenQuery); addChildResourceQueryResult(new ServicesResource(this), SERVICES, mapResponse, mapChildrenQuery, null, uriCurrent); addChildResourceQueryResult(new ClusterMembersResource(this), MEMBERS, mapResponse, mapChildrenQuery, null, uriCurrent); addChildResourceQueryResult(new ReportersResource(this), REPORTERS, mapResponse, mapChildrenQuery, null, uriCurrent); addChildResourceQueryResult(new CWebResource(this), WEB_APPS, mapResponse, mapChildrenQuery, null, uriCurrent); Object oJournal = mapChildrenQuery.get(JOURNAL); if (oJournal instanceof Map) { Map mapJournal = new LinkedHashMap<>(); Object oJournalChildren = getChildrenQuery((Map) oJournal); if (oJournalChildren instanceof Map) { Map mapJournalQuery = (Map) oJournalChildren; addChildResourceQueryResult(new JournalResource(this), RAM_JOURNAL_TYPE, mapJournal, mapJournalQuery, Collections.singletonMap(JOURNAL_TYPE, RAM_JOURNAL_TYPE), uriCurrent); addChildResourceQueryResult(new JournalResource(this), FLASH_JOURNAL_TYPE, mapJournal, mapJournalQuery, Collections.singletonMap(JOURNAL_TYPE, FLASH_JOURNAL_TYPE), uriCurrent); mapResponse.put(JOURNAL, mapJournal); } } } return mapResponse; } /** * The MBean query for ClusterMBean. * * @return the MBean query */ protected QueryBuilder getQuery() { return createQueryBuilder().withBaseQuery(CLUSTER_QUERY); } /** * The MBean query for ManagementMBean. * * @return the MBean query */ protected QueryBuilder getManagementQuery() { return createQueryBuilder() .withBaseQuery(MANAGEMENT_QUERY); } // ----- POST API (Operations) constants -------------------------------- public static final String DUMP_CLUSTER_HEAP = "dumpClusterHeap"; /** * The REST resource name and path element to configure OpenTracing. * * @since 14.1.1.0 */ public static final String CONFIGURE_TRACING = "configureTracing"; // ----- GET API (Operations) constants -------------------------------- /** * The name of operation to get Coherence cluster configuration * * @since 14.1.1.0 */ public static final String GET_CLUSTER_CONFIG = "getClusterConfig"; // ----- constants ------------------------------------------------------ public static final String ROLE = "role"; /** * Constant for {@code POST} parameter {@code tracing-ratio}. * * @since 14.1.1.0 */ public static final String TRACING_RATIO = "tracingRatio"; public static final String[] CHILD_LINKS = {SERVICES, CACHES, MEMBERS, MANAGEMENT, JOURNAL, REPORTERS, WEB_APPS, STORAGE}; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy