/* * Copyright 2015 Harald Wellmann. * * Licensed 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.ops4j.pax.cdi.spi.scan; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.xbean.finder.archive.Archive; import org.osgi.framework.Bundle; import org.osgi.framework.wiring.BundleWiring; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BundleArchive implements Archive { private static Logger log = LoggerFactory.getLogger(BundleArchive.class); private static final String CLASS_EXT = ".class"; private Bundle bundle; private Map<String, Entry> entries; private BundleFilter filter; private static class BundleArchiveEntry implements Entry { private Bundle provider; private URL path; private String name; public BundleArchiveEntry(Bundle provider, URL path, String name) { this.provider = provider; this.path = path; this.name = name; } @Override public String getName() { return name; } @Override public InputStream getBytecode() throws IOException { return path.openStream(); } public Bundle getProvider() { return provider; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof BundleArchiveEntry)) { return false; } BundleArchiveEntry other = (BundleArchiveEntry) obj; if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } } public BundleArchive(Bundle bundle) { this(bundle, new DefaultBundleFilter()); } public BundleArchive(Bundle bundle, BundleFilter filter) { this.bundle = bundle; this.entries = new HashMap<>(); this.filter = filter; } @Override public Iterator<Entry> iterator() { entries = new HashMap<>(); for (String name : bundle.adapt(BundleWiring.class).listResources( "/", "*.class", BundleWiring.LISTRESOURCES_LOCAL | BundleWiring.LISTRESOURCES_RECURSE)) { String klass = toClassName("", name); if (filter.accept(bundle, klass)) { URL url = bundle.getResource(name); BundleArchiveEntry archiveEntry = new BundleArchiveEntry(bundle, url, klass); entries.put(klass, archiveEntry); } } return entries.values().iterator(); } @Override public InputStream getBytecode(String className) throws IOException, ClassNotFoundException { Entry entry = entries.get(className); if (entry == null) { return null; } return entry.getBytecode(); } @Override public Class<?> loadClass(String className) throws ClassNotFoundException { return bundle.loadClass(className); } public Bundle getProvider(String className) { BundleArchiveEntry entry = (BundleArchiveEntry) entries.get(className); if (entry == null) { return null; } return entry.getProvider(); } private String toClassName(String classPath, String file) { String klass = null; String[] parts = file.split("!"); if (parts.length > 1) { klass = parts[1]; } else { klass = file; } if (klass.charAt(0) == '/') { klass = klass.substring(1); } String prefix = classPath; if (classPath.length() > 1) { if (classPath.charAt(0) == '/') { prefix = classPath.substring(1); } assert klass.startsWith(prefix); int startIndex = prefix.length(); if (!prefix.endsWith("/")) { startIndex++; } klass = klass.substring(startIndex); } klass = klass.replace("/", ".").replace(CLASS_EXT, ""); log.trace("file = {}, class = {}", file, klass); return klass; } }