/*
* 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.brooklyn.cli.lister;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.apache.brooklyn.api.entity.Application;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.api.policy.Policy;
import org.apache.brooklyn.api.sensor.Enricher;
import org.apache.brooklyn.core.enricher.AbstractEnricher;
import org.apache.brooklyn.core.entity.AbstractApplication;
import org.apache.brooklyn.core.entity.AbstractEntity;
import org.apache.brooklyn.core.policy.AbstractPolicy;
import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
import org.apache.brooklyn.util.core.ResourceUtils;
import org.apache.brooklyn.util.core.javalang.UrlClassLoader;
import org.apache.brooklyn.util.net.Urls;
import org.apache.brooklyn.util.os.Os;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.Beta;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
public class ClassFinder {
private static final Logger log = LoggerFactory.getLogger(ClassFinder.class);
private static final Collection<Class<?>> BORING = ImmutableList.<Class<?>>of(
Entity.class,
AbstractEntity.class,
SoftwareProcessImpl.class,
Application.class,
AbstractApplication.class,
Policy.class,
Enricher.class,
AbstractPolicy.class,
AbstractEnricher.class);
public static Predicate<Class<?>> notBoring() {
return new Predicate<Class<?>>() {
public boolean apply(Class<?> input) {
return (input != null && !BORING.contains(input));
}
};
}
public static Predicate<Class<?>> withAnnotation(final Class<? extends Annotation> annotation) {
return new Predicate<Class<?>>() {
public boolean apply(Class<?> input) {
return (input != null && input.getAnnotation(annotation) != null);
}
};
}
public static Predicate<? super Class<? extends BrooklynObject>> withClassNameMatching(final String typeRegex) {
return new Predicate<Class<?>>() {
public boolean apply(Class<?> input) {
return (input != null && input.getName() != null && input.getName().matches(typeRegex));
}
};
}
/** finds a jar at a url, or for directories, jars under a path */
@Beta
public static List<URL> toJarUrls(String url) throws MalformedURLException {
if (url==null) throw new NullPointerException("Cannot read from null");
if (url=="") throw new NullPointerException("Cannot read from empty string");
List<URL> result = Lists.newArrayList();
String protocol = Urls.getProtocol(url);
if (protocol!=null) {
// it's a URL - easy
if ("file".equals(protocol)) {
url = ResourceUtils.tidyFileUrl(url);
}
result.add(new URL(url));
} else {
// treat as file
String tidiedPath = Os.tidyPath(url);
File tidiedFile = new File(tidiedPath);
if (tidiedFile.isDirectory()) {
List<File> toscan = Lists.newLinkedList();
toscan.add(tidiedFile);
while (toscan.size() > 0) {
File file = toscan.remove(0);
if (file.isFile()) {
if (file.getName().toLowerCase().endsWith(".jar")) {
result.add(new URL("file://"+file.getAbsolutePath()));
}
} else if (file.isDirectory()) {
for (File subfile : file.listFiles()) {
toscan.add(subfile);
}
} else {
log.info("Cannot read "+file+"; not a file or directory");
}
}
} else {
result.add(tidiedFile.toURI().toURL());
}
}
return result;
}
public static <T extends BrooklynObject> Set<Class<? extends T>> findClasses(Collection<URL> urls, Class<T> clazz) {
ClassLoader classLoader = new UrlClassLoader(urls.toArray(new URL[urls.size()]));
Reflections reflections = new ConfigurationBuilder()
.addClassLoader(classLoader)
.addScanners(new SubTypesScanner(), new TypeAnnotationsScanner(), new FieldAnnotationsScanner())
.addUrls(urls)
.build();
Set<Class<? extends T>> types = reflections.getSubTypesOf(clazz);
return types;
}
}