/*
* Copyright 2008-2017 the original author or authors.
*
* 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.
*/
package org.codehaus.griffon.runtime.injection;
import com.google.inject.Binding;
import com.google.inject.Injector;
import org.codehaus.griffon.runtime.core.injection.InjectionUnitOfWork;
import javax.annotation.Nonnull;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static com.google.inject.Scopes.isSingleton;
import static griffon.util.GriffonClassUtils.hasMethodAnnotatedwith;
import static griffon.util.GriffonClassUtils.invokeAnnotatedMethod;
import static java.util.Collections.synchronizedMap;
import static java.util.Objects.requireNonNull;
/**
* @author Andres Almiray
* @since 2.6.0
*/
class InstanceTracker {
private static final String ERROR_INSTANCE_NULL = "Argument 'instance' must not be null";
private static final String ERROR_BINDING_NULL = "Argument 'binding' must not be null";
private final Map<Object, Binding<?>> instanceToKeyMap = synchronizedMap(new LinkedHashMap<Object, Binding<?>>());
private com.google.inject.Injector injector;
public void setInjector(@Nonnull Injector injector) {
this.injector = injector;
}
@Nonnull
public Injector getInjector() {
return injector;
}
@Nonnull
public <T> T track(@Nonnull Binding<?> binding, @Nonnull final T instance) {
requireNonNull(binding, ERROR_BINDING_NULL);
requireNonNull(instance, ERROR_INSTANCE_NULL);
if (hasMethodAnnotatedwith(instance, PreDestroy.class)) {
if (isSingleton(binding)) {
instanceToKeyMap.put(instance, binding);
} else {
try {
InjectionUnitOfWork.track(instance);
} catch (IllegalStateException ise) {
instanceToKeyMap.put(instance, binding);
}
}
}
return instance;
}
public <T> void release(@Nonnull T instance) {
requireNonNull(instance, ERROR_INSTANCE_NULL);
invokeAnnotatedMethod(instance, PreDestroy.class);
Binding<?> binding = instanceToKeyMap.get(instance);
if (binding != null) {
instanceToKeyMap.remove(instance);
}
}
public void releaseAll() {
List<Object> instances = new ArrayList<>();
instances.addAll(instanceToKeyMap.keySet());
instanceToKeyMap.clear();
Collections.reverse(instances);
for (Object instance : instances) {
invokeAnnotatedMethod(instance, PreDestroy.class);
}
instances.clear();
}
}