xapi.inject.impl.SingletonProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xapi-dev Show documentation
Show all versions of xapi-dev Show documentation
Everything needed to run a comprehensive dev environment.
Just type X_ and pick a service from autocomplete;
new dev modules will be added as they are built.
The only dev service not included in the uber jar is xapi-dev-maven,
as it includes all runtime dependencies of maven, adding ~4 seconds to build time,
and 6 megabytes to the final output jar size (without xapi-dev-maven, it's ~1MB).
The newest version!
/*
* Copyright 2012, We The Internet Ltd.
*
* All rights reserved.
*
* Distributed under a modified BSD License as follow:
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution, unless otherwise
* agreed to in a written document signed by a director of We The Internet Ltd.
*
* Neither the name of We The Internet nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package xapi.inject.impl;
import javax.inject.Provider;
import xapi.util.api.ProvidesValue;
import xapi.util.impl.ImmutableProvider;
/**
* A proxy class used to create a lazy-loading provider, with an efficient proxy (self-overwriting) proxy.
* .get() calls {@link #initialValue()} on first load and replaces the initializer with a pojo getter.
* This allows for easy wrapping of lazily-loaded singletons without null-checking on every access.
* @param - The type of data this var returns.
*
* @author James X Nelson ([email protected], @ajax)
*/
public abstract class SingletonProvider implements Provider, ProvidesValue{
public class NullCheckOnGet implements Provider{
/**
* Synchronized so multi-threaded platforms don't get into race conditions.
* Has no effect in javascript {yet!}
*/
@Override
public final X get() {
X init;
//start lock; could be multiple threads here at once
synchronized (this) {//compiles out of gwt
if (proxy == this){//double check lock; if we won the race condition
init = initialValue();//try to init,
if (null==init)return null;//pay for null-checks + synchro until inited
proxy = createImmutableProvider(init);//replace proxy with an immutable provider
onCreate(init);//call on create inside synchro block.
//it would be nice if we could do this outside the synchro block,
//but then any threads who lose the race condition will get back
//a partially initialized instance
}else{//another thread has already inited while we waited.
return proxy.get();//just return whatever the new proxy has
}
}
return init;
}
}
/**
* The proxy object will override itself on first load with a bare pojo-based provider.
*
* In subclasses like @LazyPojo, this proxy object is toggled to allow for efficient get() when we can.
*
*/
protected Provider proxy;
public SingletonProvider() {
proxy = new NullCheckOnGet();
}
/**
* Return a new proxy provider which just returns the set field.
*
* NEVER return an instance of {@link NullCheckOnGet},
* or you will contract a case of recursion sickness.
*
* @param init - A non-null value to provide immutably
* @return - An immutable provider.
*
* IF SUBCLASSES RETURN A PROVIDER THAT IS NOT A SUBCLASS OF
* {@link ImmutableProvider}, THEN YOU MUST OVERRIDE {@link #isSet()} AS WELL.
*/
protected Provider createImmutableProvider(X init) {
assert init != null : "Do not send null values to the immutable provider; " +
"the singleton will then return null forever.";
return new ImmutableProvider(init);
}
/**
* Tells whether or not this singleton is already set by instanceof checking
* the pojo class return from {@link #createImmutableProvider(Object)}.
*
* IF YOU OVERRIDE {@link #createImmutableProvider(Object)}, YOU MUST ALSO OVERRIDE isSet().
* @return - Whether or not our proxy class matches the expected immutable class.
*/
public boolean isSet(){
return proxy instanceof ImmutableProvider;
}
/**
* Called whenever the object is initialized.
* Will be called on the first successful {@link #get()},
* and every successful get() after a call to {@link #reset()}
* @param init
*/
protected void onCreate(X init) {
}
/**
* Called once, on first .get(). Override to provide new value, or use @LazyPojo to set(X) externally.
* @return A singleton object that will be saved and returned on every subsequent .get()
*/
protected abstract X initialValue();
/**
* This method is final so the compiler can optimize the call.
*
* This method is synchronized and null checks while the singleton is uninitialized,
* but once inited, it is unsynchronized with direct access, null-check free access to singleton.
*/
public final X get() {
return proxy.get();
}
}