/*
* Copyright 2012 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Eclipse Public License version 1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.jboss.forge.project.services;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessBean;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jboss.forge.resources.DirectoryResource;
import org.jboss.forge.resources.Resource;
import org.jboss.forge.resources.ResourceHandles;
import org.jboss.forge.resources.UnknownFileResource;
import org.jboss.forge.shell.events.PostStartup;
/**
* @author Mike Brock <cbrock@redhat.com>
*/
@Singleton
public class ResourceFactory implements Extension
{
@Inject
private Instance<BeanManager> managerInstance;
private final List<ResourceGenerator> resourceGenerators = new ArrayList<ResourceGenerator>();
/**
* Most directories will tend to contain the same type of file (such as .java, .jar, .xml, etc). So we will remember
* the last resource type we tested against and always re-try on subsequent queries before doing a comprehensive
* match.
*/
private volatile ResourceGenerator lastTypeLoaded = new ResourceGenerator()
{
@Override
public boolean matches(final String name)
{
return false;
}
};
public void setManager(@Observes final PostStartup event, final Instance<BeanManager> manager)
{
this.managerInstance = manager;
}
public void scan(@Observes final ProcessBean<Resource<?>> event, final BeanManager manager)
{
Bean<?> bean = event.getBean();
Class<?> clazz = bean.getBeanClass();
if (clazz.isAnnotationPresent(ResourceHandles.class))
{
for (String pspec : clazz.getAnnotation(ResourceHandles.class).value())
{
Pattern p = Pattern.compile(pathspecToRegEx(pspec));
CreationalContext<?> creationalCtx = manager.createCreationalContext(bean);
Resource<?> rInst = (Resource<?>) manager.getReference(bean, bean.getBeanClass(), creationalCtx);
resourceGenerators.add(new ResourceGenerator(p, rInst));
}
}
}
@SuppressWarnings("unchecked")
public <E, T extends Resource<E>> T createFromType(final Class<T> type, final E underlyingResource)
{
synchronized (this)
{
for (ResourceGenerator gen : resourceGenerators)
{
Resource<?> resource = gen.getResource();
if (type.isAssignableFrom(resource.getClass()))
{
/*
* This little <T> hack is required due to bug in javac:
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954
*/
T result = (lastTypeLoaded = gen).<T> getResource();
return (T) result.createFrom(underlyingResource);
}
}
}
return null;
}
public Resource<File> getResourceFrom(File file)
{
/**
* Special case for directories required.
*/
file = file.getAbsoluteFile();
if (file.isDirectory())
{
return new DirectoryResource(this, file);
}
final String name = file.getName();
synchronized (this)
{
if (lastTypeLoaded.matches(name))
{
return lastTypeLoaded.getResource(File.class).createFrom(file);
}
for (ResourceGenerator gen : resourceGenerators)
{
if (gen.matches(name))
{
return (lastTypeLoaded = gen).getResource(File.class).createFrom(file);
}
}
}
return new UnknownFileResource(this, file);
}
public BeanManager getManagerInstance()
{
if (managerInstance != null)
{
return managerInstance.get();
}
return null;
}
static class ResourceGenerator
{
private Pattern pattern;
private Resource<?> resource;
ResourceGenerator()
{
}
ResourceGenerator(final Pattern pattern, final Resource<?> resource)
{
this.pattern = pattern;
this.resource = resource;
}
public boolean matches(final String name)
{
return pattern.matcher(name).matches();
}
@SuppressWarnings("unchecked")
public <T> T getResource()
{
return (T) resource;
}
@SuppressWarnings({ "unchecked" })
public <T> Resource<T> getResource(final Class<T> type)
{
return (Resource<T>) resource;
}
}
private static String pathspecToRegEx(final String pathSpec)
{
return "^" + pathSpec.replaceAll("\\*", "\\.\\*").replaceAll("\\?", "\\.") + "$";
}
}