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

org.eclipse.sisu.inject.BeanCache Maven / Gradle / Ivy

There is a newer version: 3.0.0-alpha-3
Show newest version
/*******************************************************************************
 * Copyright (c) 2010-present Sonatype, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
 *******************************************************************************/
package org.eclipse.sisu.inject;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import org.eclipse.sisu.BeanEntry;

import com.google.inject.Binding;

/**
 * Atomic cache mapping {@link Binding}s to {@link BeanEntry}s; optimized for common case of single entries.
 * 

* Uses {@code ==} instead of {@code equals} to compare {@link Binding}s because we want referential equality. */ @SuppressWarnings( { "rawtypes", "unchecked" } ) final class BeanCache { // ---------------------------------------------------------------------- // Constants // ---------------------------------------------------------------------- private static final long serialVersionUID = 1L; private static final AtomicReferenceFieldUpdater MAPPING_UPDATER = AtomicReferenceFieldUpdater.newUpdater( BeanCache.class, Object.class, "mapping" ); // ---------------------------------------------------------------------- // Implementation fields // ---------------------------------------------------------------------- private volatile Object mapping; // NOSONAR private Map, BeanEntry> readCache; private volatile boolean mutated; // ---------------------------------------------------------------------- // Public methods // ---------------------------------------------------------------------- /** * Atomically creates a new {@link BeanEntry} for the given {@link Binding} reference. * * @param qualifier The qualifier * @param binding The binding * @param rank The assigned rank * @return Associated bean entry */ public BeanEntry create( final Q qualifier, final Binding binding, final int rank ) { LazyBeanEntry newBean; Object o, n; /* * Compare-and-swap approach; avoids locking without missing any updates */ do { o = mapping; if ( null == o ) { // most common case: adding the one (and-only) entry n = newBean = new LazyBeanEntry( qualifier, binding, rank ); } else if ( o instanceof LazyBeanEntry ) { final LazyBeanEntry oldBean = (LazyBeanEntry) o; if ( binding == oldBean.binding ) { return oldBean; } n = createMap( oldBean, newBean = new LazyBeanEntry( qualifier, binding, rank ) ); } else { synchronized ( this ) { final Map map = (Map) o; if ( null == ( newBean = map.get( binding ) ) ) { map.put( binding, newBean = new LazyBeanEntry( qualifier, binding, rank ) ); mutated = true; } return newBean; } } } while ( !MAPPING_UPDATER.compareAndSet( this, o, n ) ); if ( n instanceof IdentityHashMap ) { mutated = true; // entry was upgraded to map, enable readCache } return newBean; } /** * @return Read-only snapshot of the cache */ public Map, BeanEntry> flush() { if ( mutated ) { synchronized ( this ) { if ( mutated ) { readCache = (Map) ( (IdentityHashMap) mapping ).clone(); mutated = false; } } } return readCache; // NOSONAR see 'happens-before' condition above } /** * Retrieves the {@link Binding} references currently associated with {@link BeanEntry}s. * * @return Associated bindings */ public Iterable> bindings() { final Object o = mapping; if ( null == o ) { return Collections.EMPTY_SET; } else if ( o instanceof LazyBeanEntry ) { return Collections.singleton( ( (LazyBeanEntry) o ).binding ); } synchronized ( this ) { return new ArrayList( ( (Map) o ).keySet() ); } } /** * Removes the {@link BeanEntry} associated with the given {@link Binding} reference. * * @param binding The binding * @return Associated bean entry */ public BeanEntry remove( final Binding binding ) { LazyBeanEntry oldBean; Object o, n; /* * Compare-and-swap approach; avoids locking without missing any updates */ do { o = mapping; if ( null == o ) { return null; } else if ( o instanceof LazyBeanEntry ) { oldBean = (LazyBeanEntry) o; if ( binding != oldBean.binding ) { return null; } n = null; // clear single entry } else { synchronized ( this ) { oldBean = ( (Map) o ).remove( binding ); if ( null != oldBean ) { mutated = true; } return oldBean; } } } while ( !MAPPING_UPDATER.compareAndSet( this, o, n ) ); return oldBean; } // ---------------------------------------------------------------------- // Implementation methods // ---------------------------------------------------------------------- private static Map createMap( final LazyBeanEntry one, final LazyBeanEntry two ) { final Map map = new IdentityHashMap( 10 ); map.put( one.binding, one ); map.put( two.binding, two ); return map; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy