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

com.tangosol.net.internal.ScopedReferenceStore 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.net.internal;

import com.tangosol.io.ClassLoaderAware;

import com.tangosol.net.Service;
import com.tangosol.net.security.Security;

import com.tangosol.util.ConcurrentMap;
import com.tangosol.util.SegmentedConcurrentMap;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import java.util.function.Function;

/**
 * {@link ScopedReferenceStore} holds scoped {@link Object} references.
 * 

* References are scoped by ClassLoader and, optionally, Subject. * ScopedReferenceStore requires no explicit input about Subjects from its * clients. Subject scoping is configured in the operational configuration * and applies only to remote references. *

* Thread safety documented in {@link AbstractScopedReferenceStore}. * * @author jk 2015.06.25 * * @since Coherence 14.1.1 */ public class ScopedReferenceStore extends AbstractScopedReferenceStore { // ----- constructor ---------------------------------------------------- /** * Create a {@link ScopedReferenceStore} to hold references to the specified types. * * @param clsType the {@link Class} of the type of reference held in this store * @param supplierIsActive the {@link Function} that returns the active status of a reference * @param supplierName the {@link Function} that returns the name of a reference * @param supplierService the {@link Function} that returns the {@link Service} of a reference */ public ScopedReferenceStore(Class clsType, Function supplierIsActive, Function supplierName, Function supplierService) { f_clsType = clsType; f_supplierIsActive = supplierIsActive; f_supplierName = supplierName; f_supplierService = supplierService; } // ----- ScopedReferenceStore methods ----------------------------------- /** * Remove references from this store that are inactive. * * @param sName the name of the Referenceable * * @return a Collection of the ClassLoader hash codes for the ClassLoaders * associated with inactive references that have been * cleared; null if the store is empty. */ public Collection clearInactiveRefs(String sName) { Map mapByLoader = (Map) m_mapByName.get(sName); if (mapByLoader == null) { return null; // nothing stored yet } Set setHashCode; synchronized (mapByLoader) { setHashCode = mapByLoader.isEmpty() ? Collections.emptySet() : new HashSet(); for (Iterator iter = mapByLoader.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry) iter.next(); ClassLoader loaderTmp = (ClassLoader) entry.getKey(); Object oHolder = entry.getValue(); if (f_clsType.isAssignableFrom(oHolder.getClass())) { R referenceTmp = (R) entry.getValue(); if (!f_supplierIsActive.apply(referenceTmp)) { setHashCode.add(loaderTmp == null ? 0 : loaderTmp.hashCode()); iter.remove(); } } else if (oHolder instanceof SubjectScopedReference) { for (Object o : ((SubjectScopedReference) oHolder).values()) { R referenceTmp = (R) o; if (!f_supplierIsActive.apply(referenceTmp)) { setHashCode.add(loaderTmp == null ? 0 : loaderTmp.hashCode()); iter.remove(); } } } else { throw new UnsupportedOperationException(); } } } return setHashCode; } /** * Retrieve the Referenceable associated with the ClassLoader (and * Subject if applicable). * * @param sName the name of the Referenceable * @param loader the Referenceable's ClassLoader * * @return the Referenceable */ public R get(String sName, ClassLoader loader) { Map mapByLoader = (Map) m_mapByName.get(sName); if (mapByLoader != null) { synchronized (mapByLoader) { Object oHolder = mapByLoader.get(loader); if (oHolder == null || f_clsType.isAssignableFrom(oHolder.getClass())) { return (R) oHolder; } else if (oHolder instanceof SubjectScopedReference) { return (R) ((SubjectScopedReference) oHolder).get(); } else { throw new UnsupportedOperationException(); } } } return null; } /** * Retrieve all references in the store. * * @return all references */ public Collection getAll() { Set setRef = new HashSet(); Collection colLoader = m_mapByName.values(); for (Object aColLoader : colLoader) { Map mapByLoader = (Map) aColLoader; synchronized (mapByLoader) { for (Iterator iter = mapByLoader.values().iterator(); iter.hasNext(); ) { Object oHolder = iter.next(); if (oHolder instanceof SubjectScopedReference) { setRef.addAll(((SubjectScopedReference) oHolder).values()); } else if (f_clsType.isAssignableFrom(oHolder.getClass())) { setRef.add(oHolder); } else { throw new UnsupportedOperationException(); } } } } return setRef; } /** * Retrieve all references for this name. * * @param sName the name of the Referenceable * * @return all references for this name. */ public Collection getAll(String sName) { Set setRef = new HashSet(); Map mapByLoader = (Map) m_mapByName.get(sName); if (mapByLoader != null) { synchronized (mapByLoader) { Collection col = mapByLoader.values(); for (Object oHolder : col) { if (oHolder instanceof SubjectScopedReference) { setRef.addAll(((SubjectScopedReference) oHolder).values()); } else if (f_clsType.isAssignableFrom(oHolder.getClass())) { setRef.add(oHolder); } else { throw new UnsupportedOperationException(); } } } } return setRef; } /** * Store a reference with the supplied ClassLoader. * * @param reference the Referenceable * @param loader the ClassLoader */ public void put(R reference, ClassLoader loader) { ConcurrentMap mapByName = m_mapByName; String sName = f_supplierName.apply(reference); Map mapByLoader = (Map) mapByName.get(sName); if (mapByLoader == null) { mapByLoader = new WeakHashMap(); mapByName.put(sName, mapByLoader); } Service service = f_supplierService.apply(reference); if (service != null && ScopedServiceReferenceStore.isRemoteServiceType(service.getInfo().getServiceType()) && Security.SUBJECT_SCOPED) { SubjectScopedReference scopedRef = (SubjectScopedReference) mapByLoader.get(loader); if (scopedRef == null) { scopedRef = new SubjectScopedReference(); mapByLoader.put(loader, scopedRef); } scopedRef.set(reference); } else { mapByLoader.put(loader, reference); } } /** * Store a reference with the supplied ClassLoader only if * it does not already exist. * * @param reference the Referenceable * @param loader the ClassLoader * * @return the previous value associated with the specified loader, * or null if there was no mapping for the key and put succeeded */ public Object putIfAbsent(R reference, ClassLoader loader) { SegmentedConcurrentMap mapByName = m_mapByName; String sName = f_supplierName.apply(reference); Object oResult; Map mapByLoader = (Map) mapByName.get(sName); if (mapByLoader == null) { mapByLoader = new WeakHashMap(); Map mapTmp = (Map) mapByName.putIfAbsent(sName, mapByLoader); if (mapTmp != null) { mapByLoader = mapTmp; } } Service service = f_supplierService.apply(reference); if (service != null && ScopedServiceReferenceStore.isRemoteServiceType(service.getInfo().getServiceType()) && Security.SUBJECT_SCOPED) { SubjectScopedReference scopedRef = new SubjectScopedReference(); oResult = putLoaderIfAbsent(mapByLoader, loader, scopedRef); if (oResult != null) { scopedRef = (SubjectScopedReference) oResult; } oResult = scopedRef.putIfAbsent(reference); } else { oResult = putLoaderIfAbsent(mapByLoader, loader, reference); } return oResult; } /** * Remove the Referenceable from the store using the supplied * ClassLoader. * * @param reference the Referenceable * @param loader the ClassLoader * * @return whether the item was found */ public boolean release(R reference, ClassLoader loader) { Map mapByName = m_mapByName; String sName = f_supplierName.apply(reference); Map mapByLoader = (Map) mapByName.get(sName); boolean fFound = false; if (mapByLoader != null) { synchronized (mapByLoader) { Object oHolder = mapByLoader.get(loader); if (oHolder == reference) { // remove the mapping mapByLoader.remove(loader); fFound = true; } else if (oHolder instanceof SubjectScopedReference) { SubjectScopedReference scopedRef = (SubjectScopedReference) oHolder; if (scopedRef.get() == reference) { scopedRef.remove(); fFound = true; if (scopedRef.isEmpty()) { mapByLoader.remove(loader); } } } // remove the loader map if this was the last reference by // this name if (mapByLoader.isEmpty()) { mapByName.remove(sName); } } } return fFound; } /** * Remove the Referenceable from the store. * * @param reference the Referenceable * * @return whether the item was found */ public boolean release(R reference) { Map mapByName = m_mapByName; String sName = f_supplierName.apply(reference); Map mapByLoader = (Map) mapByName.get(sName); boolean fFound = false; if (mapByLoader != null) { synchronized (mapByLoader) { Collection col = mapByLoader.values(); // Assume it's a reference of Referencable references fFound = col.remove(reference); if (!fFound) { if (reference instanceof ClassLoaderAware) { return release(reference, ((ClassLoaderAware) reference).getContextClassLoader()); } // could be a reference of SubjectScopedReferences for (Iterator iter = col.iterator(); iter.hasNext(); ) { Object oHolder = iter.next(); if (oHolder instanceof SubjectScopedReference) { SubjectScopedReference scopedRef = (SubjectScopedReference) oHolder; if (scopedRef.get() == reference) { scopedRef.remove(); fFound = true; if (scopedRef.isEmpty()) { iter.remove(); } break; } } else { // no sense continuing if these aren't // SubjectScopeReferences break; } } } // remove the loader map if this was the last reference by // this name if (mapByLoader.isEmpty()) { mapByName.remove(sName); } } } return fFound; } /** * Store a loader reference with the supplied value (a reference or subject reference) * only if it does not already exist. * * @param map the map * @param loader the ClassLoader * @param oValue the Referenceable or Subject reference * * @return the previous value associated with the specified loader, * or null if there was no mapping for the key and put succeeded */ private Object putLoaderIfAbsent(Map map, ClassLoader loader, Object oValue) { Object oResult; synchronized (map) { oResult = map.get(loader); if (oResult == null) { map.put(loader, oValue); } } return oResult; } // ----- data members --------------------------------------------------- /** * The {@link Class} of the references that this store holds. */ private final Class f_clsType; /** * The {@link Function} that can return the active state of a referenced value. */ private final Function f_supplierIsActive; /** * The {@link Function} that can return the name of a referenced value. */ private final Function f_supplierName; /** * The {@link Function} that can return the {@link Service} of a referenced value. */ private final Function f_supplierService; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy