/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* ***
*
* Community License: GPL 3.0
*
* This file is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ***
*
* Available Commercial License: GraniteDS SLA 1.0
*
* This is the appropriate option if you are creating proprietary
* applications and you are not prepared to distribute and share the
* source code of your application under the GPL v3 license.
*
* Please visit http://www.granitedataservices.com/license for more
* details.
*/
package org.granite.client.tide.impl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.granite.client.tide.Context;
import org.granite.client.tide.Factory;
import org.granite.client.tide.InstanceStore;
import org.granite.client.tide.server.Component;
/**
* @author William DRAI
*/
public class SimpleInstanceStore implements InstanceStore {
protected final Context context;
protected final InstanceFactory instanceFactory;
private static final String TYPED = "__TYPED__";
private Map<String, Object> instances = new LinkedHashMap<String, Object>();
private Set<Factory<?>> appliedFactories = new HashSet<Factory<?>>();
public SimpleInstanceStore(Context context, InstanceFactory instanceFactory) {
this.context = context;
this.instanceFactory = instanceFactory;
}
public void init() {
instances.put("context", context);
instances.put("entityManager", context.getEntityManager());
instances.put("dataManager", context.getDataManager());
instances.put("eventBus", context.getEventBus());
for (Entry<String, Object> eb : context.getInitialBeans().entrySet())
instances.put(eb.getKey(), eb.getValue());
}
public <T> T set(String name, T instance) {
context.initInstance(instance, name);
instances.put(name, instance);
return instance;
}
private int NUM_TYPED_INSTANCE = 1;
public <T> T set(T instance) {
if (instance == null)
throw new NullPointerException("Cannot register null component instance");
context.initInstance(instance, null);
if (!instances.containsValue(instance))
instances.put(TYPED + (NUM_TYPED_INSTANCE++), instance);
return instance;
}
@Override
public void remove(String name) {
context.destroyInstance(instances.remove(name));
}
@Override
public void remove(Object instance) {
for (Iterator<Entry<String, Object>> ie = instances.entrySet().iterator(); ie.hasNext(); ) {
Entry<String, Object> e = ie.next();
if (e.getValue() == instance) {
ie.remove();
break;
}
}
context.destroyInstance(instance);
}
@Override
public void clear() {
for (Object instance : instances.values())
context.destroyInstance(instance);
instances.clear();
appliedFactories.clear();
}
public List<String> allNames() {
List<String> names = new ArrayList<String>(instances.size());
for (String name : instances.keySet()) {
if (!name.startsWith(TYPED))
names.add(name);
}
return names;
}
@SuppressWarnings("unchecked")
public <T> T getNoProxy(String name, Context context) {
Object instance = instances.get(name);
if (instance instanceof Component)
return null;
return (T)instance;
}
public boolean exists(String name) {
return instances.containsKey(name);
}
@SuppressWarnings("unchecked")
public <T> T byName(String name, Context context) {
T instance = (T)instances.get(name);
if (instance == null) {
Factory<?> factory = instanceFactory.forName(name, context.isGlobal());
if (factory != null) {
if (factory.isSingleton() && !context.isGlobal())
return context.getContextManager().getContext().byName(name);
instance = (T)factory.create(context);
context.initInstance(instance, name);
instances.put(name, instance);
}
}
return instance;
}
protected Object createInstance() {
return null;
}
@SuppressWarnings("unchecked")
@Override
public <T> T byType(Class<T> type, Context context) {
T instance = null;
for (Object i : instances.values()) {
if (type.isInstance(i)) {
if (instance == null)
instance = (T)i;
else
throw new RuntimeException("Ambiguous component definition for class " + type);
}
}
if (instance == null) {
List<Factory<?>> factories = instanceFactory.forType(type, context.isGlobal());
if (factories.size() > 1)
throw new RuntimeException("Ambiguous component definition for class " + type);
else if (!factories.isEmpty()) {
if (factories.get(0).isSingleton() && !context.isGlobal())
return context.getContextManager().getContext().byType(type);
if (appliedFactories.contains(factories.get(0)))
throw new IllegalStateException("Instance for type " + type + " already created by factory but not found");
instance = (T)factories.get(0).create(context);
if (!instances.containsValue(instance)) {
context.initInstance(instance, factories.get(0).getName());
String name = factories.get(0).getName() != null ? factories.get(0).getName() : TYPED + (NUM_TYPED_INSTANCE++);
instances.put(name, instance);
appliedFactories.add(factories.get(0));
}
}
}
return instance;
}
@SuppressWarnings("unchecked")
@Override
public <T> T[] allByType(Class<T> type, Context context, boolean create) {
List<Factory<?>> factories = instanceFactory.forType(type, context.isGlobal());
if (!factories.isEmpty() && !context.isGlobal() && factories.get(0).isSingleton())
return context.getContextManager().getContext().allByType(type, create);
if (create) {
for (Factory<?> factory : factories) {
if (appliedFactories.contains(factory))
continue;
String name = null;
Object instance = null;
if (factory.getName() != null) {
name = factory.getName();
instance = factory.create(context);
context.initInstance(instance, factory.getName());
}
else {
name = TYPED + (NUM_TYPED_INSTANCE++);
instance = factory.create(context);
context.initInstance(instance, null);
}
instances.put(name, instance);
appliedFactories.add(factory);
}
}
List<T> list = new ArrayList<T>();
for (Object instance : instances.values()) {
if (type.isInstance(instance))
list.add((T)instance);
}
T[] all = (T[])Array.newInstance(type, list.size());
return list.size() > 0 ? list.toArray(all) : null;
}
@Override
public Map<String, Object> allByAnnotatedWith(Class<? extends Annotation> annotationClass, Context context) {
Map<String, Object> map = new HashMap<String, Object>();
for (Entry<String, Object> entry : instances.entrySet()) {
if (entry.getValue().getClass().isAnnotationPresent(annotationClass))
map.put(entry.getKey(), entry.getValue());
}
return map.isEmpty() ? null : map;
}
public void inject(Object target, String componentName, Map<String, Object> properties) {
}
}