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

com.oracle.bedrock.runtime.coherence.CoherenceSession Maven / Gradle / Ivy

Go to download

A set of tools to manage and control Oracle Coherence 21.06 processes at runtime.

There is a newer version: 7.0.6
Show newest version
/*
 * File: CoherenceSession.java
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * The contents of this file are subject to the terms and conditions of
 * the Common Development and Distribution License 1.0 (the "License").
 *
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the License by consulting the LICENSE.txt file
 * distributed with this file, or by consulting https://oss.oracle.com/licenses/CDDL
 *
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file LICENSE.txt.
 *
 * MODIFICATIONS:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 */

package com.oracle.bedrock.runtime.coherence;

import com.oracle.bedrock.runtime.Assembly;
import com.oracle.bedrock.runtime.coherence.callables.GetSession;
import com.oracle.bedrock.runtime.coherence.callables.GetSessionCache;
import com.oracle.bedrock.runtime.concurrent.RemoteCallable;
import com.oracle.bedrock.runtime.concurrent.callable.RemoteMethodInvocation;
import com.oracle.bedrock.util.ReflectionHelper;
import com.tangosol.net.NamedCache;
import com.tangosol.net.NamedCollection;
import com.tangosol.net.NamedMap;
import com.tangosol.net.Service;
import com.tangosol.net.Session;
import com.tangosol.net.events.InterceptorRegistry;
import com.tangosol.net.topic.NamedTopic;
import com.tangosol.util.ResourceRegistry;
import com.tangosol.util.SimpleResourceRegistry;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

public class CoherenceSession
        implements Session
{
    /**
     * The {@link CoherenceClusterMember} that owns the {@link Session}
     * that this {@link CoherenceSession} represents.
     */
    private CoherenceClusterMember member;

    /**
     * The {@link Optional} {@link CoherenceCluster} that owns the {@link CoherenceClusterMember}.
     * (this is optional as the {@link CoherenceClusterMember} may not have been defined as part of a cluster).
     */
    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
    private final Optional cluster;

    /**
     * The name of the {@link com.tangosol.net.Coherence} instance that owns the {@link Session}.
     */
    private final String coherenceName;

    /**
     * The name of this {@link Session}.
     */
    private final String sessionName;

    /**
     * The {@link RemoteCallable} to use in the {@link CoherenceClusterMember}
     * to acquire the {@link Session}.
     */
    private final RemoteCallable producer;

    /**
     * The {@link RemoteMethodInvocation.Interceptor} to use for intercepting
     * and transforming remote method invocations.
     */
    private final RemoteMethodInvocation.Interceptor interceptor;

    /**
     * This session's {@link ResourceRegistry}.
     */
    private final ResourceRegistry registry;

    /**
     * Constructs a {@link CoherenceSession}.
     *
     * @param member         the {@link CoherenceClusterMember} that owns the {@link Session}
     * @param coherenceName  the name of the {@link com.tangosol.net.Coherence} instance to get the {@link Session} from
     * @param sessionName    the name of the {@link Session}
     */
    public CoherenceSession(CoherenceClusterMember  member,
                            String                  coherenceName,
                            String                  sessionName)
    {
        this(member, coherenceName, sessionName, new GetSession(coherenceName, sessionName));
    }

    /**
     * Constructs a {@link CoherenceSession}.
     *
     * @param member         the {@link CoherenceClusterMember} that owns the {@link Session}
     * @param coherenceName  the name of the {@link com.tangosol.net.Coherence} instance to get the {@link Session} from
     * @param sessionName    the name of the {@link Session}
     * @param producer       the {@link RemoteCallable} to use to obtain a {@link Session} instance
     */
    public CoherenceSession(CoherenceClusterMember  member,
                            String                  coherenceName,
                            String                  sessionName,
                            RemoteCallable producer)
    {
        this.member        = member;
        this.coherenceName = coherenceName;
        this.sessionName   = sessionName;
        this.producer      = producer;
        this.interceptor   = new SessionMethodInterceptor();
        this.registry      = new SimpleResourceRegistry();

        // determine the CoherenceCluster that the CoherenceClusterMember is part of
        Assembly assembly = member.get(Assembly.class);

        this.cluster = assembly instanceof CoherenceCluster
                       ? Optional.of((CoherenceCluster) assembly) : Optional.empty();
    }


    /**
     * Invoke the specified method remotely in the {@link CoherenceClusterMember} on the
     * {@link Session} provided by the {@link #producer}.
     *
     * @param methodName  the name of the method
     * @param arguments   the arguments for the method
     *
     * @return the result of the remote method execution
     *
     * @throws RuntimeException  if any exception occurs remotely
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    protected  T remotelyInvoke(String    methodName,
                                   Object... arguments)
    {
        // notify the interceptor that we're about make a remote invocation
        Method method = ReflectionHelper.getCompatibleMethod(Session.class, methodName, arguments);

        if (method == null)
        {
            throw new UnsupportedOperationException("Unable to locate method [" + methodName + "] with arguments ["
                                                    + Arrays.toString(arguments) + "] on Session interface");
        }
        else
        {
            interceptor.onBeforeRemoteInvocation(method, arguments);
        }

        int retryCount = 0;

        // we try the request until we've run out of operational cluster members
        while (retryCount < (cluster.isPresent() ? cluster.get().count() : 1))
        {
            // we'll need to choose a new member to perform the request when the current one is no longer operational
            // or we have to retry
            boolean chooseNewMember = !member.isOperational() || retryCount > 0;

            if (chooseNewMember)
            {
                if (cluster.isPresent())
                {
                    Optional optional = cluster.get().findAny();

                    if (optional.isPresent())
                    {
                        this.member = optional.get();
                    }
                    else
                    {
                        // there's no longer a member we can use
                        throw new IllegalStateException("The underlying Cluster no longer has available Cluster Members to perform the request ["
                                                        + methodName + "]");
                    }
                }
                else
                {
                    // we just re-throw if the member is not part of a cluster
                    throw new IllegalStateException("The underlying Cluster Member [" + member.getName()
                                                    + "] is no longer available to perform the request [" + methodName
                                                    + "]");
                }
            }

            try
            {
                // submit the remote method invocation
                CompletableFuture future = member.submit(new RemoteMethodInvocation(producer,
                                                                                    methodName,
                                                                                    arguments,
                                                                                    interceptor));

                // intercept the result after the remote invocation
                return (T) interceptor.onAfterRemoteInvocation(method, arguments, future.get());
            }
            catch (IllegalStateException e)
            {
                // retry the request with a different cluster member when the request when the submission fails
                retryCount++;
            }
            catch (RuntimeException e)
            {
                // re-throw runtime exceptions
                throw e;
            }
            catch (Exception e)
            {
                throw new RuntimeException("Failed to execute [" + methodName + "] with arguments "
                                           + Arrays.toString(arguments),
                                           interceptor.onRemoteInvocationException(method, arguments, e));
            }

        }

        throw new IllegalStateException("Failed to perform request [" + methodName + "] with arguments "
                                        + Arrays.toString(arguments) + " using [" + retryCount + "] Cluster Members");
    }


    @Override
    @SuppressWarnings({"unchecked", "rawtypes"})
    public  NamedCache getCache(String cacheName, NamedCache.Option... options)
    {
        return new CoherenceNamedCache(member,
                                       cacheName,
                                       Object.class,
                                       Object.class,
                                       new GetSessionCache(coherenceName, sessionName, cacheName));
    }

    @Override
    public  NamedTopic getTopic(String sName, NamedCollection.Option... options)
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public void close() throws Exception
    {
        throw new UnsupportedOperationException("The method Session.close() is not supported for remote execution");
    }

    @Override
    public  NamedMap getMap(String mapName, NamedMap.Option... options)
    {
        return getCache(mapName, options);
    }

    @Override
    public ResourceRegistry getResourceRegistry()
    {
        return registry;
    }

    @Override
    public InterceptorRegistry getInterceptorRegistry()
    {
        throw new UnsupportedOperationException("The method Session.getInterceptorRegistry() is not supported for remote execution");
    }

    @Override
    public boolean isMapActive(String mapName, ClassLoader loader)
    {
        return remotelyInvoke("isMapActive", mapName, null);
    }

    @Override
    public boolean isCacheActive(String cacheName, ClassLoader loader)
    {
        return remotelyInvoke("isCacheActive", cacheName, null);
    }

    @Override
    public boolean isTopicActive(String topicName, ClassLoader loader)
    {
        return remotelyInvoke("isTopicActive", topicName, null);
    }

    @Override
    public String getName()
    {
        return sessionName;
    }

    @Override
    public String getScopeName()
    {
        return remotelyInvoke("getScopeName");
    }

    @Override
    public boolean isActive()
    {
        return remotelyInvoke("isActive");
    }

    @Override
    public void activate()
    {
        remotelyInvoke("activate");
    }

    @Override
    public Service getService(String sServiceName)
    {
        throw new UnsupportedOperationException("The method Session.getService() is not supported for remote execution");
    }


    /**
     * A Coherence specific {@link RemoteMethodInvocation.Interceptor} for {@link Session} methods.
     */
    public static class SessionMethodInterceptor implements RemoteMethodInvocation.Interceptor
    {
        @Override
        public void onBeforeRemoteInvocation(Method method, Object[] arguments)
        {
            // nothing to do before invocation
        }


        @Override
        public Object onAfterRemoteInvocation(Method   method,
                                              Object[] arguments,
                                              Object   result)
        {
            return result;
        }


        @Override
        public Exception onRemoteInvocationException(Method    method,
                                                     Object[]  arguments,
                                                     Exception exception)
        {
            return exception;
        }


        @Override
        public void onBeforeInvocation(Object   instance,
                                       Method   method,
                                       Object[] arguments)
        {
            // nothing to do before invocation
        }


        @Override
        public Object onAfterInvocation(Object   instance,
                                        Method   method,
                                        Object[] arguments,
                                        Object   result)
        {
            return result;
        }


        @Override
        public Exception onInvocationException(Object    instance,
                                               Method    method,
                                               Object[]  arguments,
                                               Exception exception)
        {
            return exception;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy