com.lonepulse.icklebot.injector.Injector Maven / Gradle / Ivy
package com.lonepulse.icklebot.injector;
/*
* #%L
* IckleBot
* %%
* Copyright (C) 2013 Lonepulse
* %%
* 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.
* #L%
*/
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import com.lonepulse.icklebot.annotation.inject.InjectAll;
import com.lonepulse.icklebot.event.resolver.EventCategory;
import com.lonepulse.icklebot.injector.resolver.InjectionCategory;
import com.lonepulse.icklebot.injector.resolver.InjectionResolver;
import com.lonepulse.icklebot.injector.resolver.InjectionResolvers;
import com.lonepulse.icklebot.util.ContextUtils;
/**
* This is the common contract which all injectors must implement.
*
* @version 1.3.0
*
* @author Lahiru Sahan Jayasinghe
*/
public interface Injector {
/**
* Stores information about the injection process; such as the
* context which has requested injection and the target {@link Field}s
* in this context grouped into their categories by {@link InjectionCategory}.
*
* @version 1.1.0
*
* @author Lahiru Sahan Jayasinghe
*/
public static final class Configuration {
/**
* The mode of injection identified by
* {@link InjectionMode}.
*
* @since 1.1.0
*/
private final InjectionMode injectionMode;
/**
* The context which has requested dependency injection.
*
* @since 1.2.0
*/
private final Object context;
/**
* The target {@link Field}s in the {@link #context} grouped into their
* categories by {@link InjectionCategory}.
*
* @since 1.1.0
*/
private final Map> injectionTargets;
/**
* Creates a new instance of {@link Injector.Configuration}
* using the passed context.
*
* This is to be used in an instantiated context.
*
* @param context
* the {@link Context} which has requested dependency injection
*
* @return a new instance of {@link Injector.Configuration}
*
* @throws InjectionException
* if the supplied context is {@code null}
*
* @throws IllegalContextException
* if the given context is not of type {@link Activity} or {@link Fragment}
*
* @since 1.1.0
*/
public static Configuration newInstance(Object context) {
if(context == null)
throw new InjectionException(new IllegalArgumentException("A context must be supplied."));
if(!ContextUtils.isActivity(context)
&& !ContextUtils.isFragment(context)
&& !ContextUtils.isSupportFragment(context)) {
Set> applicableContexts = new HashSet>();
applicableContexts.add(Activity.class);
applicableContexts.add(Fragment.class);
applicableContexts.add(android.support.v4.app.Fragment.class);
throw new IllegalContextException(context, applicableContexts);
}
return new Configuration(context);
}
/**
* Constructor visibility restricted to prevent instantiation.
* Please use the factory method {@link #newInstance(Object)}.
*
* Initializes {@link #injectionTargets} to an empty {@link Map}.
*
* @since 1.1.0
*/
private Configuration(Object context) {
this.context = context;
this.injectionTargets = new HashMap>();
for (InjectionCategory injectionCategory : InjectionCategory.values())
this.injectionTargets.put(injectionCategory, new HashSet());
if(context.getClass().isAnnotationPresent(InjectAll.class))
this.injectionMode = InjectionMode.IMPLICIT;
else
this.injectionMode = InjectionMode.EXPLICIT;
Field[] fields = context.getClass().getDeclaredFields();
InjectionResolver injectionResolver
= (this.injectionMode == InjectionMode.EXPLICIT)?
InjectionResolvers.EXPLICIT :InjectionResolvers.IMPLICIT;
for (Field field : fields) {
InjectionCategory injectionCategory = injectionResolver.resolve(context, field);
injectionTargets.get(injectionCategory).add(field);
}
}
/**
* Accessor for {@link #injectionMode}.
*
* @return {@link #injectionMode}
*
* @since 1.1.0
*/
public InjectionMode getInjectionMode() {
return injectionMode;
}
/**
* Accessor for {@link #context}.
*
* @return {@link #context}
*
* @since 1.1.0
*/
public Object getContext() {
return context;
}
/**
* Accessor for {@link #injectionTargets}.
*
* @return {@link #injectionTargets}
*
* @since 1.1.0
*/
public Map> getInjectionTargets() {
return Collections.unmodifiableMap(injectionTargets);
}
/**
* Takes an {@link EventCategory} and retrieves
* the {@link Set} of {@link Field}s under that category
* as mapped in {@link #injectionTargets}.
*
* @param injectionCategory
* the fields are to be retrieved for this
* {@link EventCategory}
*
* @return the {@link Set} of {@link Field}s under
* the category, else an empty {@link Set}
*
* @since 1.1.0
*/
public Set getInjectionTargets(InjectionCategory injectionCategory) {
return Collections.unmodifiableSet(injectionTargets.get(injectionCategory));
}
}
/**
* Specifies the contract for performing injection related to a
* particular {@link InjectionCategory} over the given set of {@link Field}s.
*
* @version 1.1.0
*
* @author Lahiru Sahan Jayasinghe
*/
public static interface InjectionStrategy {
/**
*
Performs injection over the given set of {@link Field}s in
* the target {@link Context}.
*
* @param config
* the {@link Injector.Configuration} associated with the
* injection operation
*
* @return the value which is to be injected
*
* @since 1.1.0
*/
public abstract void run(Injector.Configuration config);
}
/**
*
Takes an {@link Injector.Configuration} and injects the resources
* which this injector is responsible for.
*
* @param config
* the {@link Injector.Configuration} which for this injector
*
* @throws InjectionException
* if the injection operation failed
*
* @since 1.1.0
*/
public abstract void inject(final Injector.Configuration config)
throws InjectionException;
}