com.caucho.config.inject.InjectScanManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resin-kernel Show documentation
Show all versions of resin-kernel Show documentation
Kernel for Resin Java Application Server
The newest version!
/*
* Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source 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 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.config.inject;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.inject.spi.AnnotatedType;
import com.caucho.config.program.ConfigProgram;
import com.caucho.config.reflect.ReflectionAnnotatedFactory;
import com.caucho.loader.DynamicClassLoader;
import com.caucho.loader.EnvironmentClassLoader;
import com.caucho.loader.enhancer.ScanClass;
import com.caucho.loader.enhancer.ScanListener;
import com.caucho.util.CharBuffer;
import com.caucho.vfs.Path;
/**
* The web beans container for a given environment.
*/
class InjectScanManager implements ScanListener {
private static final Logger log
= Logger.getLogger(InjectScanManager.class.getName());
private InjectManager _injectManager;
private final HashMap _scanRootMap
= new HashMap();
private final ArrayList _pendingScanRootList
= new ArrayList();
private final ConcurrentHashMap _scanClassMap
= new ConcurrentHashMap();
private final ConcurrentHashMap _annotationMap
= new ConcurrentHashMap();
private final ArrayList _immediateResourceList
= new ArrayList();
private NameKey _nameKey = new NameKey();
private boolean _isCustomExtension;
private ArrayList _pendingScanClassList
= new ArrayList();
InjectScanManager(InjectManager injectManager)
{
_injectManager = injectManager;
}
/**
* Returns the injection manager.
*/
public InjectManager getInjectManager()
{
return _injectManager;
}
/**
* True if a custom extension exists.
*/
public void setIsCustomExtension(boolean isCustomExtension)
{
_isCustomExtension = isCustomExtension;
if (isCustomExtension) {
for (InjectScanClass scanClass : _scanClassMap.values()) {
scanClass.register();
}
}
}
public boolean isCustomExtension()
{
return _isCustomExtension;
}
public ArrayList getPendingScanRootList()
{
ArrayList contextList
= new ArrayList(_pendingScanRootList);
_pendingScanRootList.clear();
return contextList;
}
public boolean isPending()
{
return _pendingScanClassList.size() > 0 || _pendingScanRootList.size() > 0;
}
public void addDiscoveredClass(InjectScanClass injectScanClass)
{
if (! _pendingScanClassList.contains(injectScanClass)) {
_pendingScanClassList.add(injectScanClass);
}
}
/**
* discovers pending beans.
*/
public void discover()
{
ArrayList pendingScanClassList
= new ArrayList(_pendingScanClassList);
_pendingScanClassList.clear();
for (InjectScanClass scanClass : pendingScanClassList) {
getInjectManager().discoverBean(scanClass);
}
}
//
// ScanListener
/**
* Since CDI doesn't enhance, it's priority 1
*/
@Override
public int getScanPriority()
{
return 1;
}
@Override
public boolean isRootScannable(Path root, String packageRoot)
{
ScanRootContext context = _scanRootMap.get(root);
List beansXmlOverride = _injectManager.getBeansXmlOverride(root);
Path scanRoot = root;
if (packageRoot != null) {
scanRoot = scanRoot.lookup(packageRoot.replace('.', '/'));
}
if (beansXmlOverride == null) {
// TODO Should resin-beans.xml be included in this check?
if (packageRoot != null) {
if (! scanRoot.lookup("beans.xml").canRead()
&& ! scanRoot.lookup("META-INF/beans.xml").canRead()) {
return false;
}
} else if (! (root.lookup("META-INF/beans.xml").canRead()
|| (root.getFullPath().endsWith("WEB-INF/classes/")
&& root.lookup("../beans.xml").canRead()))) {
return false;
}
}
if (context == null) {
context = new ScanRootContext(scanRoot, packageRoot);
_scanRootMap.put(root, context);
_pendingScanRootList.add(context);
}
if (context.isScanComplete())
return false;
else {
if (log.isLoggable(Level.FINER))
log.finer("CanDI scanning " + root.getURL());
context.setScanComplete(true);
return true;
}
}
/**
* Checks if the class can be a simple class
*/
@Override
public ScanClass scanClass(Path root,
String packageRoot,
String className,
int modifiers)
{
// ioc/0j0k - package private allowed
if (Modifier.isPrivate(modifiers))
return null;
else {
InjectScanClass scanClass = createScanClass(className);
scanClass.setScanClass();
return scanClass;
}
}
InjectScanClass getScanClass(String className)
{
return _scanClassMap.get(className);
}
InjectScanClass createScanClass(String className)
{
InjectScanClass scanClass = _scanClassMap.get(className);
if (scanClass == null) {
scanClass = new InjectScanClass(className, this);
InjectScanClass oldScanClass;
oldScanClass = _scanClassMap.putIfAbsent(className, scanClass);
if (oldScanClass != null)
scanClass = oldScanClass;
}
return scanClass;
}
/**
* Loads an annotation for scanning.
*/
public AnnType loadAnnotation(char[] buffer, int offset, int length)
throws ClassNotFoundException
{
NameKey key = _nameKey;
key.init(buffer, offset, length); // new NameKey(buffer, offset, length);
AnnType annType = _annotationMap.get(key);
if (annType != null)
return annType;
ClassLoader loader = getInjectManager().getClassLoader();
String className = new String(buffer, offset, length);
Class> cl = Class.forName(className, false, loader);
annType = new AnnType(cl);
_annotationMap.put(key.dup(), annType);
return annType;
}
@Override
public boolean isScanMatchAnnotation(CharBuffer string)
{
return false;
}
@Override
public void classMatchEvent(EnvironmentClassLoader loader,
Path root,
String className)
{
}
public void addImmediateResource(InjectScanClass injectScanClass)
{
ClassLoader classLoader = _injectManager.getClassLoader();
if (classLoader instanceof DynamicClassLoader) {
DynamicClassLoader dynLoader = (DynamicClassLoader) classLoader;
ClassLoader tmpLoader = dynLoader.getNewTempClassLoader();
Thread thread = Thread.currentThread();
ClassLoader oldLoader = thread.getContextClassLoader();
try {
thread.setContextClassLoader(dynLoader);
Class> cl = tmpLoader.loadClass(injectScanClass.getClassName());
AnnotatedType> annType
= ReflectionAnnotatedFactory.introspectType(cl);
for (Annotation ann : cl.getAnnotations()) {
InjectionPointHandler handler
= _injectManager.getInjectionPointHandler(ann.annotationType());
if (handler != null) {
ConfigProgram program = handler.introspectType(annType);
if (program != null)
program.inject(null, null);
}
}
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
} finally {
thread.setContextClassLoader(oldLoader);
}
}
}
@Override
public String toString()
{
return getClass().getSimpleName() + "[" + _injectManager + "]";
}
static class NameKey {
private char[] _buffer;
private int _offset;
private int _length;
NameKey(char[] buffer, int offset, int length)
{
init(buffer, offset, length);
}
NameKey()
{
}
void init(char[] buffer, int offset, int length)
{
_buffer = buffer;
_offset = offset;
_length = length;
}
public NameKey dup()
{
char[] buffer = new char[_length];
System.arraycopy(_buffer, _offset, buffer, 0, _length);
//_buffer = buffer;
//_offset = 0;
return new NameKey(buffer, 0, _length);
}
public int hashCode()
{
char[] buffer = _buffer;
int offset = _offset;
int length = _length;
int hash = length;
for (length--; length >= 0; length--) {
char value = buffer[offset + length];
hash = 65521 * hash + value;
}
return hash;
}
public boolean equals(Object o)
{
if (!(o instanceof NameKey))
return false;
NameKey key = (NameKey) o;
if (_length != key._length)
return false;
char[] bufferA = _buffer;
char[] bufferB = key._buffer;
int offsetA = _offset;
int offsetB = key._offset;
for (int i = _length - 1; i >= 0; i--) {
if (bufferA[offsetA + i] != bufferB[offsetB + i])
return false;
}
return true;
}
@Override
public String toString()
{
return this.getClass().getSimpleName() + "[" + new String(_buffer,
_offset,
_length);
}
}
static class AnnType {
private Class> _type;
private Annotation[] _annotations;
AnnType(Class> type)
{
_type = type;
}
public Class> getType()
{
return _type;
}
public Annotation[] getAnnotations()
{
if (_annotations == null)
_annotations = _type.getAnnotations();
return _annotations;
}
}
}