| /* |
| * 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.camel.core.osgi.impl; |
| |
| import java.io.BufferedInputStream; |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.lang.reflect.Method; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Dictionary; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| import org.apache.camel.CamelContext; |
| import org.apache.camel.Component; |
| import org.apache.camel.Converter; |
| import org.apache.camel.TypeConverter; |
| import org.apache.camel.TypeConverterLoaderException; |
| import org.apache.camel.impl.converter.AnnotationTypeConverterLoader; |
| import org.apache.camel.impl.scan.AnnotatedWithPackageScanFilter; |
| import org.apache.camel.model.DataFormatDefinition; |
| import org.apache.camel.spi.ComponentResolver; |
| import org.apache.camel.spi.DataFormat; |
| import org.apache.camel.spi.DataFormatResolver; |
| import org.apache.camel.spi.Injector; |
| import org.apache.camel.spi.Language; |
| import org.apache.camel.spi.LanguageResolver; |
| import org.apache.camel.spi.PackageScanFilter; |
| import org.apache.camel.spi.TypeConverterLoader; |
| import org.apache.camel.spi.TypeConverterRegistry; |
| import org.apache.camel.util.IOHelper; |
| import org.apache.camel.util.ObjectHelper; |
| import org.apache.camel.util.StringHelper; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleActivator; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.BundleEvent; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.ServiceRegistration; |
| import org.osgi.framework.wiring.BundleCapability; |
| import org.osgi.framework.wiring.BundleWire; |
| import org.osgi.framework.wiring.BundleWiring; |
| import org.osgi.util.tracker.BundleTracker; |
| import org.osgi.util.tracker.BundleTrackerCustomizer; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import static org.osgi.framework.wiring.BundleRevision.PACKAGE_NAMESPACE; |
| |
| public class Activator implements BundleActivator, BundleTrackerCustomizer<Object> { |
| |
| public static final String META_INF_COMPONENT = "META-INF/services/org/apache/camel/component/"; |
| public static final String META_INF_LANGUAGE = "META-INF/services/org/apache/camel/language/"; |
| public static final String META_INF_LANGUAGE_RESOLVER = "META-INF/services/org/apache/camel/language/resolver/"; |
| public static final String META_INF_DATAFORMAT = "META-INF/services/org/apache/camel/dataformat/"; |
| public static final String META_INF_TYPE_CONVERTER = "META-INF/services/org/apache/camel/TypeConverter"; |
| public static final String META_INF_TYPE_CONVERTER_LOADER = "META-INF/services/org/apache/camel/TypeConverterLoader"; |
| public static final String META_INF_FALLBACK_TYPE_CONVERTER = "META-INF/services/org/apache/camel/FallbackTypeConverter"; |
| public static final String EXTENDER_NAMESPACE = "osgi.extender"; |
| public static final String CAMEL_EXTENDER = "org.apache.camel"; |
| |
| private static final Logger LOG = LoggerFactory.getLogger(Activator.class); |
| |
| private BundleTracker<?> tracker; |
| private final Map<Long, List<BaseService>> resolvers = new ConcurrentHashMap<>(); |
| private long bundleId; |
| |
| // Map from package name to the capability we export for this package |
| private final Map<String, BundleCapability> packageCapabilities = new HashMap<>(); |
| |
| public void start(BundleContext context) throws Exception { |
| LOG.info("Camel activator starting"); |
| cachePackageCapabilities(context); |
| bundleId = context.getBundle().getBundleId(); |
| BundleContext systemBundleContext = context.getBundle(0).getBundleContext(); |
| tracker = new BundleTracker<>(systemBundleContext, Bundle.ACTIVE, this); |
| tracker.open(); |
| LOG.info("Camel activator started"); |
| } |
| |
| public void stop(BundleContext context) throws Exception { |
| LOG.info("Camel activator stopping"); |
| tracker.close(); |
| packageCapabilities.clear(); |
| LOG.info("Camel activator stopped"); |
| } |
| |
| /** |
| * Caches the package capabilities that are needed for a set of interface classes |
| */ |
| private void cachePackageCapabilities(BundleContext context) { |
| BundleWiring ourWiring = context.getBundle().adapt(BundleWiring.class); |
| List<BundleCapability> ourExports = ourWiring.getCapabilities(PACKAGE_NAMESPACE); |
| for (BundleCapability ourExport : ourExports) { |
| String ourPkgName = (String) ourExport.getAttributes().get(PACKAGE_NAMESPACE); |
| packageCapabilities.put(ourPkgName, ourExport); |
| } |
| for (BundleWire w : ourWiring.getRequiredWires(PACKAGE_NAMESPACE)) { |
| BundleCapability cap = w.getCapability(); |
| String ourPkgName = (String) cap.getAttributes().get(PACKAGE_NAMESPACE); |
| packageCapabilities.put(ourPkgName, cap); |
| } |
| } |
| |
| public Object addingBundle(Bundle bundle, BundleEvent event) { |
| LOG.debug("Bundle started: {}", bundle.getSymbolicName()); |
| if (extenderCapabilityWired(bundle)) { |
| List<BaseService> r = new ArrayList<>(); |
| registerComponents(bundle, r); |
| registerLanguages(bundle, r); |
| registerDataFormats(bundle, r); |
| registerTypeConverterLoader(bundle, r); |
| for (BaseService service : r) { |
| service.register(); |
| } |
| resolvers.put(bundle.getBundleId(), r); |
| } |
| |
| return bundle; |
| } |
| |
| private boolean extenderCapabilityWired(Bundle bundle) { |
| BundleWiring wiring = bundle.adapt(BundleWiring.class); |
| if (wiring == null) { |
| return true; |
| } |
| List<BundleWire> requiredWires = wiring.getRequiredWires(EXTENDER_NAMESPACE); |
| for (BundleWire requiredWire : requiredWires) { |
| if (CAMEL_EXTENDER.equals(requiredWire.getCapability().getAttributes().get(EXTENDER_NAMESPACE))) { |
| if (this.bundleId == requiredWire.getProviderWiring().getBundle().getBundleId()) { |
| LOG.debug("Camel extender requirement of bundle {} correctly wired to this implementation", bundle.getBundleId()); |
| return true; |
| } else { |
| LOG.info("Not processing bundle {} as it requires a camel extender but is not wired to the this implementation", bundle.getBundleId()); |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) { |
| } |
| |
| public void removedBundle(Bundle bundle, BundleEvent event, Object object) { |
| LOG.debug("Bundle stopped: {}", bundle.getSymbolicName()); |
| List<BaseService> r = resolvers.remove(bundle.getBundleId()); |
| if (r != null) { |
| for (BaseService service : r) { |
| service.unregister(); |
| } |
| } |
| } |
| |
| protected void registerComponents(Bundle bundle, List<BaseService> resolvers) { |
| if (canSee(bundle, Component.class)) { |
| Map<String, String> components = new HashMap<>(); |
| for (Enumeration<?> e = bundle.getEntryPaths(META_INF_COMPONENT); e != null && e.hasMoreElements();) { |
| String path = (String) e.nextElement(); |
| LOG.debug("Found entry: {} in bundle {}", path, bundle.getSymbolicName()); |
| String name = path.substring(path.lastIndexOf("/") + 1); |
| components.put(name, path); |
| } |
| if (!components.isEmpty()) { |
| resolvers.add(new BundleComponentResolver(bundle, components)); |
| } |
| } |
| } |
| |
| protected void registerLanguages(Bundle bundle, List<BaseService> resolvers) { |
| if (canSee(bundle, Language.class)) { |
| Map<String, String> languages = new HashMap<>(); |
| for (Enumeration<?> e = bundle.getEntryPaths(META_INF_LANGUAGE); e != null && e.hasMoreElements();) { |
| String path = (String) e.nextElement(); |
| LOG.debug("Found entry: {} in bundle {}", path, bundle.getSymbolicName()); |
| String name = path.substring(path.lastIndexOf("/") + 1); |
| languages.put(name, path); |
| } |
| if (!languages.isEmpty()) { |
| resolvers.add(new BundleLanguageResolver(bundle, languages)); |
| } |
| for (Enumeration<?> e = bundle.getEntryPaths(META_INF_LANGUAGE_RESOLVER); e != null && e.hasMoreElements();) { |
| String path = (String) e.nextElement(); |
| LOG.debug("Found entry: {} in bundle {}", path, bundle.getSymbolicName()); |
| String name = path.substring(path.lastIndexOf("/") + 1); |
| resolvers.add(new BundleMetaLanguageResolver(bundle, name, path)); |
| } |
| } |
| } |
| |
| protected void registerDataFormats(Bundle bundle, List<BaseService> resolvers) { |
| if (canSee(bundle, DataFormat.class)) { |
| Map<String, String> dataformats = new HashMap<>(); |
| for (Enumeration<?> e = bundle.getEntryPaths(META_INF_DATAFORMAT); e != null && e.hasMoreElements();) { |
| String path = (String) e.nextElement(); |
| LOG.debug("Found entry: {} in bundle {}", path, bundle.getSymbolicName()); |
| String name = path.substring(path.lastIndexOf("/") + 1); |
| dataformats.put(name, path); |
| } |
| if (!dataformats.isEmpty()) { |
| resolvers.add(new BundleDataFormatResolver(bundle, dataformats)); |
| } |
| } |
| } |
| |
| protected void registerTypeConverterLoader(Bundle bundle, List<BaseService> resolvers) { |
| if (canSee(bundle, TypeConverter.class)) { |
| URL url1 = bundle.getEntry(META_INF_TYPE_CONVERTER); |
| URL url2 = bundle.getEntry(META_INF_TYPE_CONVERTER_LOADER); |
| URL url3 = bundle.getEntry(META_INF_FALLBACK_TYPE_CONVERTER); |
| if (url2 != null) { |
| LOG.debug("Found TypeConverterLoader in bundle {}", bundle.getSymbolicName()); |
| Set<Class<?>> classes = new LinkedHashSet<>(); |
| Set<String> packages = getConverterPackages(bundle.getEntry(META_INF_TYPE_CONVERTER_LOADER)); |
| |
| if (LOG.isTraceEnabled()) { |
| LOG.trace("Found {} {} packages: {}", packages.size(), META_INF_TYPE_CONVERTER_LOADER, packages); |
| } |
| for (String pkg : packages) { |
| |
| if (StringHelper.isClassName(pkg)) { |
| // its a FQN class name so load it directly |
| LOG.trace("Loading {} class", pkg); |
| try { |
| Class<?> clazz = bundle.loadClass(pkg); |
| BundleTypeConverterLoader bundleTypeConverterLoader = |
| new BundleTypeConverterLoader(bundle, url3 != null); |
| bundleTypeConverterLoader.setTypeConverterLoader((TypeConverterLoader)clazz.getDeclaredConstructor().newInstance()); |
| resolvers.add(bundleTypeConverterLoader); |
| BundleTypeConverterLoader fallBackBundleTypeConverterLoader = |
| new BundleTypeConverterLoader(bundle, url3 != null); |
| // the class could be found and loaded so continue to next |
| resolvers.add(fallBackBundleTypeConverterLoader); |
| continue; |
| } catch (Throwable t) { |
| // Ignore |
| LOG.trace("Failed to load " + pkg + " class due " + t.getMessage() + ". This exception will be ignored.", t); |
| } |
| } |
| } |
| |
| } else if (url1 != null || url3 != null) { |
| LOG.debug("Found TypeConverter in bundle {}", bundle.getSymbolicName()); |
| resolvers.add(new BundleTypeConverterLoader(bundle, url3 != null)); |
| } |
| } |
| } |
| |
| /** |
| * Check if bundle can see the given class |
| */ |
| protected boolean canSee(Bundle bundle, Class<?> clazz) { |
| if (bundle.getBundleId() == bundleId) { |
| // Need extra handling of camel core as it does not import the api |
| return true; |
| } |
| BundleCapability packageCap = packageCapabilities.get(clazz.getPackage().getName()); |
| if (packageCap != null) { |
| BundleWiring wiring = bundle.adapt(BundleWiring.class); |
| List<BundleWire> imports = wiring.getRequiredWires(PACKAGE_NAMESPACE); |
| for (BundleWire importWire : imports) { |
| if (packageCap.equals(importWire.getCapability())) { |
| return true; |
| } |
| } |
| } |
| |
| // it may be running outside real OSGi container such as when unit testing with camel-test-blueprint |
| // then we need to use a different canSee algorithm that works outside real OSGi |
| if (bundle.getBundleId() >= 0) { |
| Bundle root = bundle.getBundleContext().getBundle(0); |
| if (root != null && "org.apache.felix.connect".equals(root.getSymbolicName())) { |
| return checkCompat(bundle, clazz); |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Check if bundle can see the given class used by camel-test-blueprint |
| */ |
| protected static boolean checkCompat(Bundle bundle, Class<?> clazz) { |
| // Check bundle compatibility |
| try { |
| if (bundle.loadClass(clazz.getName()) != clazz) { |
| return false; |
| } |
| } catch (Throwable t) { |
| return false; |
| } |
| return true; |
| } |
| |
| protected static class BundleComponentResolver extends BaseResolver<Component> implements ComponentResolver { |
| |
| private final Map<String, String> components; |
| |
| public BundleComponentResolver(Bundle bundle, Map<String, String> components) { |
| super(bundle, Component.class); |
| this.components = components; |
| } |
| |
| public Component resolveComponent(String name, CamelContext context) throws Exception { |
| return createInstance(name, components.get(name), context); |
| } |
| |
| public void register() { |
| doRegister(ComponentResolver.class, "component", components.keySet()); |
| } |
| } |
| |
| protected static class BundleLanguageResolver extends BaseResolver<Language> implements LanguageResolver { |
| |
| private final Map<String, String> languages; |
| |
| public BundleLanguageResolver(Bundle bundle, Map<String, String> languages) { |
| super(bundle, Language.class); |
| this.languages = languages; |
| } |
| |
| public Language resolveLanguage(String name, CamelContext context) { |
| return createInstance(name, languages.get(name), context); |
| } |
| |
| public void register() { |
| doRegister(LanguageResolver.class, "language", languages.keySet()); |
| } |
| } |
| |
| protected static class BundleMetaLanguageResolver extends BaseResolver<LanguageResolver> implements LanguageResolver { |
| |
| private final String name; |
| private final String path; |
| |
| public BundleMetaLanguageResolver(Bundle bundle, String name, String path) { |
| super(bundle, LanguageResolver.class); |
| this.name = name; |
| this.path = path; |
| } |
| |
| public Language resolveLanguage(String name, CamelContext context) { |
| LanguageResolver resolver = createInstance(this.name, path, context); |
| return resolver.resolveLanguage(name, context); |
| } |
| |
| public void register() { |
| doRegister(LanguageResolver.class, "resolver", name); |
| } |
| } |
| |
| protected static class BundleDataFormatResolver extends BaseResolver<DataFormat> implements DataFormatResolver { |
| |
| private final Map<String, String> dataformats; |
| |
| public BundleDataFormatResolver(Bundle bundle, Map<String, String> dataformats) { |
| super(bundle, DataFormat.class); |
| this.dataformats = dataformats; |
| } |
| |
| @Override |
| public DataFormat resolveDataFormat(String name, CamelContext context) { |
| DataFormat dataFormat = createInstance(name, dataformats.get(name), context); |
| if (dataFormat == null) { |
| dataFormat = createDataFormat(name, context); |
| } |
| |
| return dataFormat; |
| } |
| |
| @Override |
| public DataFormat createDataFormat(String name, CamelContext context) { |
| return createInstance(name, dataformats.get(name), context); |
| } |
| |
| public DataFormatDefinition resolveDataFormatDefinition(String name, CamelContext context) { |
| return null; |
| } |
| |
| @Override |
| public void register() { |
| doRegister(DataFormatResolver.class, "dataformat", dataformats.keySet()); |
| } |
| } |
| |
| protected static class BundleTypeConverterLoader extends BaseResolver<TypeConverter> implements TypeConverterLoader { |
| |
| private TypeConverterLoader loader = new Loader(); |
| private final Bundle bundle; |
| private final boolean hasFallbackTypeConverter; |
| |
| public BundleTypeConverterLoader(Bundle bundle, boolean hasFallbackTypeConverter) { |
| super(bundle, TypeConverter.class); |
| ObjectHelper.notNull(bundle, "bundle"); |
| this.bundle = bundle; |
| this.hasFallbackTypeConverter = hasFallbackTypeConverter; |
| } |
| |
| public void setTypeConverterLoader(TypeConverterLoader typeConverterloader) { |
| this.loader = typeConverterloader; |
| } |
| |
| public synchronized void load(TypeConverterRegistry registry) throws TypeConverterLoaderException { |
| // must be synchronized to ensure we don't load type converters concurrently |
| // which cause Camel apps to fails in OSGi thereafter |
| try { |
| loader.load(registry); |
| } catch (Exception e) { |
| throw new TypeConverterLoaderException("Cannot load type converters using OSGi bundle: " + bundle.getBundleId(), e); |
| } |
| } |
| |
| public void register() { |
| if (hasFallbackTypeConverter) { |
| // The FallbackTypeConverter should have a higher ranking |
| doRegister(TypeConverterLoader.class, Constants.SERVICE_RANKING, 100); |
| } else { |
| // The default service ranking is Integer(0); |
| doRegister(TypeConverterLoader.class); |
| } |
| } |
| |
| class Loader extends AnnotationTypeConverterLoader { |
| |
| Loader() { |
| super(null); |
| } |
| |
| public void load(TypeConverterRegistry registry) throws TypeConverterLoaderException { |
| PackageScanFilter test = new AnnotatedWithPackageScanFilter(Converter.class, true); |
| Set<Class<?>> classes = new LinkedHashSet<>(); |
| Set<String> packages = getConverterPackages(bundle.getEntry(META_INF_TYPE_CONVERTER)); |
| |
| if (LOG.isTraceEnabled()) { |
| LOG.trace("Found {} {} packages: {}", packages.size(), META_INF_TYPE_CONVERTER, packages); |
| } |
| // if we only have camel-core on the classpath then we have already pre-loaded all its type converters |
| // but we exposed the "org.apache.camel.core" package in camel-core. This ensures there is at least one |
| // packageName to scan, which triggers the scanning process. That allows us to ensure that we look for |
| // META-INF/services in all the JARs. |
| if (packages.size() == 1 && "org.apache.camel.core".equals(packages.iterator().next())) { |
| LOG.debug("No additional package names found in classpath for annotated type converters."); |
| // no additional package names found to load type converters so break out |
| return; |
| } |
| |
| // now filter out org.apache.camel.core as its not needed anymore (it was just a dummy) |
| packages.remove("org.apache.camel.core"); |
| |
| for (String pkg : packages) { |
| |
| if (StringHelper.isClassName(pkg)) { |
| // its a FQN class name so load it directly |
| LOG.trace("Loading {} class", pkg); |
| try { |
| Class<?> clazz = bundle.loadClass(pkg); |
| classes.add(clazz); |
| // the class could be found and loaded so continue to next |
| continue; |
| } catch (Throwable t) { |
| // Ignore |
| LOG.trace("Failed to load " + pkg + " class due " + t.getMessage() + ". This exception will be ignored.", t); |
| } |
| } |
| |
| // its not a FQN but a package name so scan for classes in the bundle |
| Enumeration<URL> e = bundle.findEntries("/" + pkg.replace('.', '/'), "*.class", true); |
| while (e != null && e.hasMoreElements()) { |
| String path = e.nextElement().getPath(); |
| String externalName = path.substring(path.charAt(0) == '/' ? 1 : 0, path.indexOf('.')).replace('/', '.'); |
| LOG.trace("Loading {} class", externalName); |
| try { |
| Class<?> clazz = bundle.loadClass(externalName); |
| if (test.matches(clazz)) { |
| classes.add(clazz); |
| } |
| } catch (Throwable t) { |
| // Ignore |
| LOG.trace("Failed to load " + externalName + " class due " + t.getMessage() + ". This exception will be ignored.", t); |
| } |
| } |
| } |
| |
| // load the classes into type converter registry |
| LOG.debug("Found {} @Converter classes to load", classes.size()); |
| for (Class<?> type : classes) { |
| if (LOG.isTraceEnabled()) { |
| LOG.trace("Loading converter class: {}", ObjectHelper.name(type)); |
| } |
| loadConverterMethods(registry, type); |
| } |
| |
| // register fallback converters |
| URL fallbackUrl = bundle.getEntry(META_INF_FALLBACK_TYPE_CONVERTER); |
| if (fallbackUrl != null) { |
| LOG.debug("Found {} to load the FallbackTypeConverter", META_INF_FALLBACK_TYPE_CONVERTER); |
| TypeConverter tc = createInstance("FallbackTypeConverter", fallbackUrl, registry.getInjector()); |
| registry.addFallbackTypeConverter(tc, false); |
| } |
| |
| // now clear the maps so we do not hold references |
| visitedClasses.clear(); |
| visitedURIs.clear(); |
| } |
| } |
| |
| } |
| |
| protected abstract static class BaseResolver<T> extends BaseService { |
| |
| private final Class<T> type; |
| |
| public BaseResolver(Bundle bundle, Class<T> type) { |
| super(bundle); |
| this.type = type; |
| } |
| |
| protected T createInstance(String name, String path, CamelContext context) { |
| if (path == null) { |
| return null; |
| } |
| URL url = bundle.getEntry(path); |
| LOG.trace("The entry {}'s url is {}", name, url); |
| //Setup the TCCL with Camel context application class loader |
| ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); |
| try { |
| ClassLoader newClassLoader = context.getApplicationContextClassLoader(); |
| if (newClassLoader != null) { |
| Thread.currentThread().setContextClassLoader(newClassLoader); |
| } |
| T answer = createInstance(name, url, context.getInjector()); |
| if (answer != null) { |
| initBundleContext(answer); |
| } |
| return answer; |
| } finally { |
| Thread.currentThread().setContextClassLoader(oldClassLoader); |
| } |
| } |
| |
| private void initBundleContext(T answer) { |
| try { |
| Method method = answer.getClass().getMethod("setBundleContext", BundleContext.class); |
| if (method != null) { |
| method.invoke(answer, bundle.getBundleContext()); |
| } |
| } catch (Exception e) { |
| // ignore |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| protected T createInstance(String name, URL url, Injector injector) { |
| try { |
| Properties properties = loadProperties(url); |
| String classname = (String) properties.get("class"); |
| Class type = bundle.loadClass(classname); |
| if (!this.type.isAssignableFrom(type)) { |
| throw new IllegalArgumentException("Type is not a " + this.type.getName() + " implementation. Found: " + type.getName()); |
| } |
| return (T) injector.newInstance(type, false); |
| } catch (ClassNotFoundException e) { |
| throw new IllegalArgumentException("Invalid URI, no " + this.type.getName() + " registered for scheme : " + name, e); |
| } |
| } |
| |
| } |
| |
| protected abstract static class BaseService { |
| |
| protected final Bundle bundle; |
| private ServiceRegistration<?> reg; |
| |
| protected BaseService(Bundle bundle) { |
| this.bundle = bundle; |
| } |
| |
| public abstract void register(); |
| |
| protected void doRegister(Class<?> type, String key, Collection<String> value) { |
| doRegister(type, key, value.toArray(new String[value.size()])); |
| } |
| |
| protected void doRegister(Class<?> type, String key, Object value) { |
| Dictionary<String, Object> props = new Hashtable<>(); |
| props.put(key, value); |
| doRegister(type, props); |
| } |
| |
| protected void doRegister(Class<?> type) { |
| doRegister(type, null); |
| } |
| |
| protected void doRegister(Class<?> type, Dictionary<String, ?> props) { |
| reg = bundle.getBundleContext().registerService(type.getName(), this, props); |
| } |
| |
| public void unregister() { |
| reg.unregister(); |
| } |
| } |
| |
| protected static Properties loadProperties(URL url) { |
| Properties properties = new Properties(); |
| BufferedInputStream reader = null; |
| try { |
| reader = IOHelper.buffered(url.openStream()); |
| properties.load(reader); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } finally { |
| IOHelper.close(reader, "properties", LOG); |
| } |
| return properties; |
| } |
| |
| protected static Set<String> getConverterPackages(URL resource) { |
| Set<String> packages = new LinkedHashSet<>(); |
| if (resource != null) { |
| BufferedReader reader = null; |
| try { |
| reader = IOHelper.buffered(new InputStreamReader(resource.openStream())); |
| while (true) { |
| String line = reader.readLine(); |
| if (line == null) { |
| break; |
| } |
| line = line.trim(); |
| if (line.startsWith("#") || line.length() == 0) { |
| continue; |
| } |
| StringTokenizer iter = new StringTokenizer(line, ","); |
| while (iter.hasMoreTokens()) { |
| String name = iter.nextToken().trim(); |
| if (name.length() > 0) { |
| packages.add(name); |
| } |
| } |
| } |
| } catch (Exception ignore) { |
| // Do nothing here |
| } finally { |
| IOHelper.close(reader, null, LOG); |
| } |
| } |
| return packages; |
| } |
| |
| } |
| |
| |