/*
* Copyright 2013 The Solmix Project
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.gnu.org/licenses/
* or see the FSF site: http://www.fsf.org.
*/
package org.solmix.runtime.extension;
import static org.solmix.commons.util.DataUtils.isEmpty;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.solmix.runtime.Extension;
/**
*
* @author solmix.f@gmail.com
* @version $Id$ 2014年8月5日
*/
public class DefaultExtensionLoader<T> implements ExtensionLoader<T>
{
private final ExtensionManagerImpl extensionManager;
private final Class<T> type;
private String defaultName;
private Map<String,ExtensionInfo> cached;
private final Object cachedLock=new Object();
public DefaultExtensionLoader(Class<T> type,ExtensionManagerImpl extensionManager){
this.extensionManager=extensionManager;
this.type=type;
}
/**
* {@inheritDoc}
*
* @see org.solmix.runtime.extension.ExtensionLoader#getDefault()
*/
@Override
public T getDefault() {
getExtensionInfos();
if(isEmpty(defaultName))
return null;
return getExtension(defaultName);
}
private Map<String, ExtensionInfo> getExtensionInfos() {
if (cached == null) {
synchronized (cachedLock) {
loadExtensions();
}
}
return cached;
}
/**
*
*/
private void loadExtensions() {
Extension e = type.getAnnotation(Extension.class);
if (e != null) {
String defName = e.name();
if (defName != null)
defaultName = defName.trim();
}
if (cached == null) {
Map<String, ExtensionInfo> cachedExtensions = new HashMap<String, ExtensionInfo>();
Set<ExtensionInfo> infos = extensionManager.getExtensionInfos(type);
for (ExtensionInfo info : infos) {
Class<?> clazz = info.getClassObject(null);
if (clazz != null) {
Extension anno = clazz.getAnnotation(Extension.class);
if (anno != null && anno.name() != null) {
String implemntor = anno.name().trim();
if (cachedExtensions.get(implemntor) != null) {
ExtensionInfo older = cachedExtensions.get(implemntor);
throw new IllegalStateException("Class:["
+ clazz.getName() + "] with name:["
+ implemntor + "],conflict and class:["
+ older.getClassname() + "]");
} else {
cachedExtensions.put(anno.name().trim(), info);
}
}
}
}
cached=cachedExtensions;
}
}
/**
* {@inheritDoc}
*
* @see org.solmix.runtime.extension.ExtensionLoader#getDefaultName()
*/
@Override
public String getDefaultName() {
getExtensionInfos();
return defaultName;
}
/**
* {@inheritDoc}
*
* @see org.solmix.runtime.extension.ExtensionLoader#getExtension(java.lang.String)
*/
@Override
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name is null");
ExtensionInfo info = getExtensionInfos().get(name);
if (info != null) {
if (info.getLoadedObject() == null) {
extensionManager.createExtension(info);
}
return type.cast(info.getLoadedObject());
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.solmix.runtime.extension.ExtensionLoader#getExtensionName(java.lang.Class)
*/
@Override
public String getExtensionName(Class<?> clazz) {
Extension e=clazz.getAnnotation(Extension.class);
if(e!=null){
return e.name().trim();
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.solmix.runtime.extension.ExtensionLoader#getExtensionName(java.lang.Object)
*/
@Override
public String getExtensionName(T t) {
return getExtensionName(t.getClass());
}
/**
* {@inheritDoc}
*
* @see org.solmix.runtime.extension.ExtensionLoader#hasExtension(java.lang.String)
*/
@Override
public boolean hasExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name is null");
try {
return getExtensionInfos().get(name) != null;
} catch (Throwable t) {
return false;
}
}
/**
* {@inheritDoc}
*
* @see org.solmix.runtime.extension.ExtensionLoader#getLoadedExtensions()
*/
@Override
public Set<String> getLoadedExtensions() {
getExtensionInfos();
return Collections.unmodifiableSet(new TreeSet<String>(cached.keySet()));
}
public void addExtension(String name,ExtensionInfo info){
getExtensionInfos();
synchronized (cachedLock) {
cached.put(name, info);
}
}
/**
* {@inheritDoc}
*
* @see org.solmix.runtime.extension.ExtensionLoader#addExtension(java.lang.String, java.lang.Class)
*/
@Override
public void addExtension(String name, Class<T> clazz) {
getExtensionInfos();
if(type.isAssignableFrom(clazz)){
throw new IllegalStateException("Input type " +
clazz + "not implement Extension " + type);
}
if(clazz.isInterface()) {
throw new IllegalStateException("Input type " +
clazz + "can not be interface!");
}
if(cached.containsKey(name)){
throw new IllegalStateException("Extension name " +
name + " already existed(Extension " + type + ")!");
}
synchronized (cachedLock) {
ExtensionInfo info = new ExtensionInfo(Thread.currentThread().getContextClassLoader());
info.setClassname(clazz.getName());
info.setInterfaceName(type.getName());
info.setDeferred(true);
cached.put(name, info);
}
}
}