blob: 7a1cdc6bf6560a2e9027070f7fcfcd5e142e170c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.webbeans.arquillian.standalone;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.webbeans.spi.BDABeansXmlScanner;
import org.apache.webbeans.spi.ScannerService;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ArchivePath;
import org.jboss.shrinkwrap.api.Filters;
import org.jboss.shrinkwrap.api.Node;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.ArchiveAsset;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.FileAsset;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
/**
*
*/
public class OwbArquillianScannerService implements ScannerService
{
private final static String WEB_INF_CLASS_FOLDER = "/WEB-INF/classes/";
private boolean beansXmlBdaScanningEnabled;
private Archive archive;
private UrlSet beansXmls = new UrlSet();
private Set<Class<?>> beanClasses = new HashSet<Class<?>>();
public OwbArquillianScannerService()
{
this.beansXmlBdaScanningEnabled = false;
}
@Override
public BDABeansXmlScanner getBDABeansXmlScanner()
{
return null;
}
@Override
public void init(Object object)
{
// nothing to do
}
public void setArchive(Archive archive)
{
this.archive = archive;
}
@Override
public void scan()
{
if (archive == null)
{
return;
}
final String archiveName = archive.getName();
if (archiveName.endsWith(".jar"))
{
scanJarArchive(archive);
}
else if (archiveName.endsWith(".war"))
{
scanWebArchive(archive);
}
else
{
throw new IllegalStateException("Scanning of Archive " + archive.getClass().getName() + "Not yet implemented");
}
}
@Override
public Set<URL> getBeanXmls()
{
return beansXmls;
}
@Override
public Set<Class<?>> getBeanClasses()
{
return beanClasses;
}
@Override
public void release()
{
beansXmls.clear();
beanClasses.clear();
}
@Override
public boolean isBDABeansXmlScanningEnabled()
{
return beansXmlBdaScanningEnabled;
}
// --------- private implementation -----------
private void scanWebArchive(final Archive<?> archive)
{
URL webBeansXmlUrl = getBeanXmlUrl(archive, "WEB-INF/beans.xml");
if (webBeansXmlUrl != null)
{
beansXmls.add(webBeansXmlUrl);
}
URL metainfBeansXmlUrl = getBeanXmlUrl(archive, WEB_INF_CLASS_FOLDER + "META-INF/beans.xml");
if (metainfBeansXmlUrl != null)
{
beansXmls.add(metainfBeansXmlUrl);
}
if (metainfBeansXmlUrl != null || webBeansXmlUrl != null)
{
// in this case we need to scan the WEB-INF/classses folder for .class files
Map<ArchivePath, Node> classes = archive.getContent(Filters.include(WEB_INF_CLASS_FOLDER + ".*\\.class"));
scanClasses(classes, WEB_INF_CLASS_FOLDER);
}
// and now scan all the jars in the WAR
Map<ArchivePath, Node> jars = archive.getContent(Filters.include("/WEB-INF/lib/.*\\.jar"));
for (Map.Entry<ArchivePath, Node> jarEntry : jars.entrySet())
{
Asset asset = jarEntry.getValue().getAsset();
if (asset instanceof FileAsset)
{
FileAsset fileAsset = (FileAsset) asset;
if (fileAsset.getSource().getName().endsWith(".jar"))
{
Archive<?> fileArchive = ShrinkWrap.createFromZipFile(JavaArchive.class, fileAsset.getSource());
asset = new ArchiveAsset(fileArchive, ZipExporter.class);
}
}
if (asset instanceof ArchiveAsset)
{
ArchiveAsset archiveAsset = (ArchiveAsset) asset;
JavaArchive jarArchive = (JavaArchive) archiveAsset.getArchive();
scanJarArchive(jarArchive);
}
}
}
private void scanJarArchive(final Archive<?> archive)
{
URL beansXmlUrl = getBeanXmlUrl(archive, "META-INF/beans.xml");
if (beansXmlUrl == null)
{
// this is not a CDI archive
return;
}
// otherwise we store it for later use
beansXmls.add(beansXmlUrl);
// and now add all classes
Map<ArchivePath, Node> classes = archive.getContent(Filters.include(".*\\.class"));
scanClasses(classes, null);
}
/**
*
* @param classes the scanned classes
* @param classBasePath the base class in which the classes are, or null if they are directly in the root
*/
private void scanClasses(Map<ArchivePath, Node> classes, String classBasePath)
{
for (Map.Entry<ArchivePath, Node> classEntry : classes.entrySet())
{
String className = classEntry.getKey().get();
if (classBasePath != null && className.startsWith(WEB_INF_CLASS_FOLDER))
{
className = className.substring(WEB_INF_CLASS_FOLDER.length());
}
// cut off leading slashes
if (className.startsWith("/"))
{
className = className.substring(1);
}
// cut off ".class"
className = className.substring(0, className.length() - ".class".length());
className = className.replace('/', '.');
try
{
Class<?> beanClass = Class.forName(className);
beanClasses.add(beanClass);
}
catch (ClassNotFoundException cnfe)
{
throw new RuntimeException("Could not scan class", cnfe);
}
}
}
private URL getBeanXmlUrl(Archive archive, String beansXmlPath)
{
final Node beansXml = archive.get(beansXmlPath);
if (beansXml == null)
{
return null;
}
try
{
String urlLocation = "archive://" + archive.getName() + "/" + beansXmlPath;
return new URL(null, urlLocation, new URLStreamHandler()
{
@Override
protected URLConnection openConnection(URL u) throws IOException
{
return new URLConnection(u)
{
@Override
public void connect() throws IOException
{}
@Override
public InputStream getInputStream() throws IOException
{
return beansXml.getAsset().openStream();
}
};
};
});
}
catch (Exception e)
{
RuntimeException runtimeException;
if (e instanceof RuntimeException)
{
runtimeException = (RuntimeException) e;
}
else
{
runtimeException = new RuntimeException("Error while parsing beans.xml location", e);
}
throw runtimeException;
}
}
public void clear()
{
archive = null;
beansXmls = new UrlSet();
beanClasses = new HashSet<Class<?>>();
}
}