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

it.tidalwave.netbeans.util.AsLookupSupport Maven / Gradle / Ivy

There is a newer version: 1.0.13
Show newest version
    /***********************************************************************************************************************
 *
 * blueBill Core - open source birding
 * Copyright (C) 2009-2011 by Tidalwave s.a.s. (http://www.tidalwave.it)
 *
 ***********************************************************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 *
 ***********************************************************************************************************************
 *
 * WWW: http://bluebill.tidalwave.it
 * SCM: https://kenai.com/hg/bluebill~core-src
 *
 **********************************************************************************************************************/
package it.tidalwave.netbeans.util;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.Arrays;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import it.tidalwave.util.As;
import it.tidalwave.util.NotFoundException;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
import it.tidalwave.netbeans.capabilitiesprovider.LookupFactory;
import it.tidalwave.netbeans.capabilitiesprovider.ThreadLookupBinder;
    
/***********************************************************************************************************************
 *
 * FIXME: move to OpenBlueSky
 * 
 * @author  Fabrizio Giudici
 * @version $Id$
 *
 **********************************************************************************************************************/
public class AsLookupSupport implements As, Lookup.Provider, Serializable
  {
    private static final Logger log = LoggerFactory.getLogger(AsLookupSupport.class);
    
    private static final long serialVersionUID = 5704964038450988L;
    
    /**
     * The cache seems to give some advantage on Android. E.g. blueBill rendering taxa displaynames on a Motorola
     * Milestone with Android 2.2 takes about 5msec without cache and 0msec with cache.
     * TODO: enable it with a system property, so we can enable it only with Android.
     * TODO: theoretically, it is possible to inject a mutable Lookup, so we should set up a listener to the Lookup
     * and invalidate the cache upon changes. This is probably too much for many cases in which Lookups are used in
     * a static fashion Maybe we could use the listener if another system property is enabled.
     */
    private static final boolean USE_CACHE = true;
    
    /** 
     * The owner is usually the object itself, but it can be another in case this class is used in a composition for
     * delegation. 
     */
    private final Object owner;
    
    /** Those capabilities specific of this instance. */
    private final Object[] instanceCapabilities;

    /**
     * Transient: there's no reason in making lookup serializable as it contains capabilities injected by the
     * context that could be not meaningful in the target deserialization context. Injected capabilities will be 
     * recreated at the first getLookup() call after deserialization).
     */
    @CheckForNull
    private transient Lookup lookup;
    
    @CheckForNull
    private transient Map, Object> cache; 
    
    @CheckForNull
    private transient Lookup threadLocalLookup;
    
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public AsLookupSupport()
      {
        this(new Object[0]);
        threadLocalLookup = ThreadLookupBinder.getLookup();
      }
    
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public AsLookupSupport (final @Nonnull Object[] instanceCapabilities)
      {
        this.owner = this;
        this.instanceCapabilities = instanceCapabilities.clone();
        threadLocalLookup = ThreadLookupBinder.getLookup();
      }
    
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public AsLookupSupport (final @Nonnull Object owner)
      {
        this(owner, new Object[0]);
        threadLocalLookup = ThreadLookupBinder.getLookup();
      }
    
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    public AsLookupSupport (final @Nonnull Object owner, final @Nonnull Object[] instanceCapabilities)
      {
        this.owner = owner;
        this.instanceCapabilities = instanceCapabilities.clone();
        threadLocalLookup = ThreadLookupBinder.getLookup();
      }
    
    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Nonnull
    public final synchronized Lookup getLookup()
      {
        if (lookup == null)
          {
            lookup = createLookup();
          }

        return lookup;
      }
    
    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Nonnull
    public final  T as (final @Nonnull Class type)
      {
        return as(type, As.Defaults.throwAsException(type));
      }
    
    /*******************************************************************************************************************
     *
     * {@inheritDoc}
     *
     ******************************************************************************************************************/
    @Nonnull
    public  T as (final @Nonnull Class type, final @Nonnull NotFoundBehaviour notFoundBehaviour)
      {
        final long time = System.currentTimeMillis();
        
        try
          {
            
            T result = null;
            
            if (!USE_CACHE)
              {
                result = getLookup().lookup(type);               
              }
            else
              {
                synchronized (this)
                  {
                    if (cache == null)   
                      {
                        cache = new WeakHashMap, Object>();
                      }

                    result = type.cast(cache.get(type));

                    if (result == null)
                      {
                        result = getLookup().lookup(type);   

                        if (result != null)
                          {
                            cache.put(type, result);
                          }
                      }
                  }
              }
            
            return (result != null) ? result : notFoundBehaviour.run(new NotFoundException("No " + type.getName() + " in " + this));
          }
        finally
          {
            log.trace(">>>> {}.as({}) took {} msec.", new Object[]{ toShortString(), type.getSimpleName(), System.currentTimeMillis() - time });
          }
      }    

    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    protected Lookup createLookup() 
      {
        final long time = System.currentTimeMillis();
        Lookup result = LookupFactory.createLookup(owner, Lookups.fixed(instanceCapabilities));
        
        if (threadLocalLookup != null)
          {
            result = LookupFactory.createLookup(threadLocalLookup, this, result);
            threadLocalLookup = null;
          }
        
        log.trace(">>>> createLookup() - for {} took {} msec.", toShortString(), System.currentTimeMillis() - time);
        return result;
      }
    
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Override @Nonnull
    public String toString()
      {
        return String.format("%s@%x[%s]", getClass().getSimpleName(), 
                                          System.identityHashCode(this), 
                                          Arrays.toString(instanceCapabilities));
      }
  
    /*******************************************************************************************************************
     *
     *
     ******************************************************************************************************************/
    @Nonnull
    private String toShortString()
      {
        return String.format("%s@%x", getClass().getSimpleName(), System.identityHashCode(this));
      }
  }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy