You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by an...@apache.org on 2015/09/14 08:25:16 UTC
incubator-tamaya git commit: Added initial early draft version of CL
aware service context implementation.
Repository: incubator-tamaya
Updated Branches:
refs/heads/master aa36ff9f3 -> 459510e33
Added initial early draft version of CL aware service context implementation.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/commit/459510e3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/tree/459510e3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tamaya/diff/459510e3
Branch: refs/heads/master
Commit: 459510e33974ec28f9c9df9868fa4693c9ae905a
Parents: aa36ff9
Author: anatole <an...@apache.org>
Authored: Mon Sep 14 08:24:36 2015 +0200
Committer: anatole <an...@apache.org>
Committed: Mon Sep 14 08:24:57 2015 +0200
----------------------------------------------------------------------
sandbox/classloader-support/pom.xml | 53 ++++
.../internal/CLAwareServiceContext.java | 191 ++++++++++++
.../apache/tamaya/clsupport/internal/Item.java | 30 ++
.../tamaya/clsupport/internal/ItemSet.java | 140 +++++++++
.../clsupport/internal/ServiceContainer.java | 287 +++++++++++++++++++
.../org.apache.tamaya.spi.ServiceContext | 19 ++
6 files changed, 720 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/459510e3/sandbox/classloader-support/pom.xml
----------------------------------------------------------------------
diff --git a/sandbox/classloader-support/pom.xml b/sandbox/classloader-support/pom.xml
new file mode 100644
index 0000000..c5cb480
--- /dev/null
+++ b/sandbox/classloader-support/pom.xml
@@ -0,0 +1,53 @@
+<!--
+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 current 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.tamaya.ext</groupId>
+ <artifactId>tamaya-sandbox</artifactId>
+ <version>0.2-incubating-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <artifactId>tamaya-classloader-support</artifactId>
+ <name>Apache Tamaya Modules -Classloader Support</name>
+ <description>Apache Tamaya Classloader Support registers a ConfigurationContext that leverages
+ classloader hierarchies. Also visibility of features and components is aligned with the
+ corresponding hierarchy of classloaders.</description>
+ <packaging>jar</packaging>
+
+ <properties>
+ <jdkVersion>1.7</jdkVersion>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tamaya</groupId>
+ <artifactId>tamaya-java7-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/459510e3/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/CLAwareServiceContext.java
----------------------------------------------------------------------
diff --git a/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/CLAwareServiceContext.java b/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/CLAwareServiceContext.java
new file mode 100644
index 0000000..7d418d9
--- /dev/null
+++ b/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/CLAwareServiceContext.java
@@ -0,0 +1,191 @@
+/*
+ * 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.tamaya.clsupport.internal;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.spi.ServiceContext;
+
+import javax.annotation.Priority;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Created by Anatole on 06.09.2015.
+ */
+@Priority(250)
+public class CLAwareServiceContext extends AbstractClassloaderAwareItemLoader<ServiceContainer>
+ implements ServiceContext{
+
+ public static final String PREFIX = "META-INF/services/";
+
+ /**
+ * Singletons as valid for this classloader. Other classloaders or parent contexts may have alternate
+ * singleton instances being active.
+ */
+ private final Map<Class<?>, Object> singletons = new ConcurrentHashMap<>();
+
+ public CLAwareServiceContext(){
+ super();
+ }
+
+ public CLAwareServiceContext(String resourceLocation) {
+ super();
+ }
+
+ public CLAwareServiceContext(String resourceLocation, ClassLoader classLoader) {
+ super(classLoader);
+ }
+
+
+ @Override
+ protected ServiceContainer createItem(ClassLoader classLoader) {
+ return new ServiceContainer(classLoader);
+ }
+
+ @Override
+ protected void updateItem(ServiceContainer currentContainer, ClassLoader classLoader) {
+
+ }
+
+ @Override
+ public int ordinal() {
+ return 100;
+ }
+
+ @Override
+ public <T> T getService(Class<T> serviceType) {
+ Object cached = singletons.get(serviceType);
+ if (cached == null) {
+ Collection<? extends T> services = getServices(serviceType);
+ if (services.isEmpty()) {
+ cached = null;
+ } else {
+ cached = getServiceWithHighestPriority(services, serviceType);
+ }
+ if(cached!=null) {
+ singletons.put(serviceType, cached);
+ }
+ }
+ return serviceType.cast(cached);
+ }
+
+ public <T> T getService(Class<T> serviceType, ClassLoader classLoader) {
+ ClassLoader cl = classLoader;
+ List<T> services = new ArrayList<>();
+ while(cl!=null) {
+ ServiceContainer container = getItemNoParent(classLoader, true);
+ services.addAll(container.getServices(serviceType));
+ }
+ return select(services, serviceType);
+ }
+
+ private <T> T select(Collection<T> services, Class<T> serviceType) {
+ return getServiceWithHighestPriority(services, serviceType);
+ }
+
+ @Override
+ public <T> Collection<T> getServices(Class<T> serviceType) {
+ return getServices(serviceType, AbstractClassloaderAwareItemLoader.getDefaultClassLoader());
+ }
+
+ public <T> Collection<T> getServices(Class<T> serviceType, ClassLoader classLoader) {
+ List<T> services = new ArrayList<>();
+ ClassLoader cl = classLoader;
+ List<ServiceContainer> containers = new ArrayList<>();
+ while(cl!=null) {
+ ServiceContainer container = getItemNoParent(cl, true);
+ containers.add(container);
+ cl = cl.getParent();
+ }
+ List<ServiceContainer> prevContainers = new ArrayList<>();
+ Collections.reverse(containers);
+ for(ServiceContainer container: containers) {
+ if (!container.isTypeLoaded(serviceType)) {
+ container.loadServices(serviceType, prevContainers);
+ prevContainers.add(container);
+ services.addAll(container.getServices(serviceType));
+ }
+ }
+ // TODO Sort services
+ // TODO Get first
+ return services;
+ }
+
+ /**
+ * @param services to scan
+ * @param <T> type of the service
+ *
+ * @return the service with the highest {@link javax.annotation.Priority#value()}
+ *
+ * @throws ConfigException if there are multiple service implementations with the maximum priority
+ */
+ private <T> T getServiceWithHighestPriority(Collection<? extends T> services, Class<T> serviceType) {
+
+ // we do not need the priority stuff if the list contains only one element
+ if (services.size() == 1) {
+ return services.iterator().next();
+ }
+
+ Integer highestPriority = null;
+ int highestPriorityServiceCount = 0;
+ T highestService = null;
+
+ for (T service : services) {
+ int prio = getPriority(service);
+ if (highestPriority == null || highestPriority < prio) {
+ highestService = service;
+ highestPriorityServiceCount = 1;
+ highestPriority = prio;
+ } else if (highestPriority == prio) {
+ highestPriorityServiceCount++;
+ }
+ }
+
+ if (highestPriorityServiceCount > 1) {
+ throw new ConfigException(MessageFormat.format("Found {0} implementations for Service {1} with Priority {2}: {3}",
+ highestPriorityServiceCount,
+ serviceType.getName(),
+ highestPriority,
+ services));
+ }
+
+ return highestService;
+ }
+
+ /**
+ * Checks the given instance for a @Priority annotation. If present the annotation's value s evaluated. If no such
+ * annotation is present, a default priority is returned (1);
+ * @param o the instance, not null.
+ * @return a priority, by default 1.
+ */
+ public static int getPriority(Object o){
+ int prio = 0;
+ Priority priority = o.getClass().getAnnotation(Priority.class);
+ if (priority != null) {
+ prio = priority.value();
+ }
+ return prio;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/459510e3/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/Item.java
----------------------------------------------------------------------
diff --git a/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/Item.java b/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/Item.java
new file mode 100644
index 0000000..9ed1f2b
--- /dev/null
+++ b/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/Item.java
@@ -0,0 +1,30 @@
+/*
+ * 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.tamaya.clsupport.internal;
+
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * Created by Anatole on 08.09.2015.
+ */
+public interface Item<T extends Item<T>> {
+ <T> void update(ClassLoader classLoader, Enumeration<URL> resources, List<T> itemsMatching);
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/459510e3/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/ItemSet.java
----------------------------------------------------------------------
diff --git a/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/ItemSet.java b/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/ItemSet.java
new file mode 100644
index 0000000..53b8e67
--- /dev/null
+++ b/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/ItemSet.java
@@ -0,0 +1,140 @@
+/*
+ * 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.tamaya.clsupport.internal;
+
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Class that acts as a container for items loaded/evaialbe/bound to exactly one classloader.
+ */
+final class ItemSet<T> implements Iterable<T>{
+ /** The managed items. */
+ private Set<T> items = new HashSet<>();
+ /** the corresponding classloader. */
+ private WeakReference<ClassLoader> classLoaderRef;
+ /** Timestamp in ms, when the last time the resource set was updated/checked for additional items. */
+ private long lastUpdate;
+
+ /**
+ * Creates a new resource set.
+ * @param cl the classloader, not null.
+ * @param items the items to be added, not null.
+ */
+ public ItemSet(ClassLoader cl, Collection<T> items){
+ this.classLoaderRef = new WeakReference<ClassLoader>(Objects.requireNonNull(cl));
+ this.items.addAll(items);
+ }
+
+ /**
+ * Removes all items.
+ */
+ public void clear(){
+ Set<T> res = this.items;
+ if(res!=null) {
+ res.clear();
+ }
+ }
+
+ /**
+ * Adds the given items. If the resource set is not active this method return false and
+ * no resource will be added.
+ * @param resources the items to be added, not null.
+ * @return true, if adding was succesful.
+ */
+ public boolean addResources(Collection<T> resources) {
+ if(!isActive()){
+ return false;
+ }
+ Set<T> res = this.items;
+ if(res!=null) {
+ res.addAll(resources);
+ this.lastUpdate = System.currentTimeMillis();
+ }
+ return true;
+ }
+
+ public boolean contains(T resource) {
+ return getItems().contains(resource);
+ }
+
+ public Set<T> getItems(){
+ if(classLoaderRef==null) {
+ return Collections.emptySet();
+ }
+ return Collections.unmodifiableSet(this.items);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return getItems().iterator();
+ }
+
+ /**
+ * Checks, if the referenced classloader was garbage collected.
+ * @return true if the referenced classloader was garbage collected.
+ */
+ public boolean isActive(){
+ return classLoaderRef==null;
+ }
+
+ /**
+ * Gets the timestamp, when the resource was updated the last time.
+ * @return the timestamp, when the resource was updated the last time.
+ */
+ public long getLastUpdate(){
+ return lastUpdate;
+ }
+
+ /**
+ * Updates the items, e.g. by adding new items found.
+ * @param resources the updated items.
+ */
+ public void update(Collection<T> resources) {
+ if(classLoaderRef!=null) {
+ if (classLoaderRef.get()==null) {
+ this.items = null;
+ }
+ else{
+ if(this.items !=null){
+ Set<T> newRes = new HashSet<>(resources.size());
+ newRes.addAll(resources);
+ this.items = newRes;
+ }
+ }
+ this.lastUpdate = System.currentTimeMillis();
+ }
+ }
+
+
+ @Override
+ public String toString() {
+ return "ItemSet{" +
+ "items=" + items +
+ ", classLoaderRef=" + classLoaderRef +
+ ", lastUpdate=" + lastUpdate +
+ '}';
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/459510e3/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/ServiceContainer.java
----------------------------------------------------------------------
diff --git a/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/ServiceContainer.java b/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/ServiceContainer.java
new file mode 100644
index 0000000..a8293be
--- /dev/null
+++ b/sandbox/classloader-support/src/main/java/org/apache/tamaya/clsupport/internal/ServiceContainer.java
@@ -0,0 +1,287 @@
+/*
+ * 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.tamaya.clsupport.internal;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceConfigurationError;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Created by Anatole on 08.09.2015.
+ */
+class ServiceContainer {
+
+ private static final Logger LOG = Logger.getLogger(ServiceContainer.class.getName());
+
+ private static final String PREFIX = "META-INF/services/";
+
+ // The access control context taken when the ServiceLoader is created
+ private final AccessControlContext acc;
+
+ private WeakReference<ClassLoader> classLoaderRef;
+
+ /**
+ * List current services loaded using this classloader, per class.
+ */
+ private final Map<Class<?>, Map<String, Object>> servicesLoaded = new ConcurrentHashMap<>();
+
+ /**
+ * List current services loaded using this classloader, per class.
+ */
+ private final Map<Class, List<URL>> configsLoaded = new ConcurrentHashMap<>();
+
+ ServiceContainer(ClassLoader classLoader){
+ acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
+ this.classLoaderRef = new WeakReference<>(classLoader);
+ }
+
+ public ClassLoader getClassLoader(){
+ ClassLoader cl = classLoaderRef.get();
+ if(cl==null){
+ throw new IllegalStateException("Classloader reference removed, not active anynire.");
+ }
+ return cl;
+ }
+
+
+ public <T> void loadServices(Class<?> type,
+ Collection<ServiceContainer> preceedingContainers){
+ Map<String, Object> services = (Map<String, Object>)this.servicesLoaded.get(type);
+ if(services==null) {
+ services = new LinkedHashMap<>();
+ this.servicesLoaded.put(type, services);
+ }
+ loop:for(URL config:getConfigs(type)) {
+ for (ServiceContainer cont : preceedingContainers) {
+ if (cont.getConfigs(type).contains(config)) {
+ LOG.finer("Ignoring already loaded config: " + config);
+ continue loop;
+ }
+ }
+ Collection<String> serviceNames = parse(type, config);
+ for (String s : serviceNames) {
+ for (ServiceContainer cont : preceedingContainers) {
+ if (cont.containsService(type, s)) {
+ LOG.finest("Ignoring duplicate service: " + s);
+ continue;
+ }
+ }
+ LOG.info("Loading component: " + s);
+ services.put(s, create(type, s));
+ }
+ }
+ }
+
+ private Collection<URL> getConfigs(Class<?> type){
+ List<URL> result = this.configsLoaded.get(type);
+ if(result==null){
+ ClassLoader cl = this.classLoaderRef.get();
+ if(cl==null){
+ throw new IllegalStateException("CLassLoader dereferenced already.");
+ }
+ result = new ArrayList<>();
+ try {
+ Enumeration<URL> resources = cl.getResources(PREFIX + type.getName());
+ while (resources.hasMoreElements()) {
+ result.add(resources.nextElement());
+ }
+ }
+ catch(Exception e){
+ LOG.log(Level.WARNING, "Failed to read service config for " + type.getName()+" from " + cl, e);
+ }
+ this.configsLoaded.put(type, result);
+ LOG.log(Level.FINE, "Found service config for " + type.getName() + ": " + result);
+ }
+ return result;
+ }
+
+ private boolean containsService(Class<?> type, String serviceClassName) {
+ Map<String,Object> services = servicesLoaded.get(type);
+ if(services==null){
+ return false;
+ }
+ return services.containsKey(serviceClassName);
+ }
+
+
+ private <S> S create(Class<S> serviceType, String className) {
+ Class<?> c = null;
+ ClassLoader classLoader = getClassLoader();
+ try {
+ c = Class.forName(className, false, classLoader);
+ } catch (ClassNotFoundException x) {
+ fail(serviceType,
+ "Provider " + className + " not found");
+ }
+ if (!serviceType.isAssignableFrom(c)) {
+ fail(serviceType,
+ "Provider " + className + " not a subtype");
+ }
+ try {
+ S p = serviceType.cast(c.newInstance());
+ return p;
+ } catch (Throwable x) {
+ fail(serviceType,
+ "Provider " + className + " could not be instantiated",
+ x);
+ }
+ throw new Error(); // This cannot happen
+ }
+
+ public <T> Collection<T> getServices(Class<T> serviceType) {
+ Map<String, Object> services = this.servicesLoaded.get(serviceType);
+ if(services!=null) {
+ return (Collection<T>)services.values();
+ }
+ return Collections.emptySet();
+ }
+
+ public boolean isTypeLoaded(Class<?> serviceType){
+ return this.servicesLoaded.containsKey(serviceType);
+ }
+
+ public Collection<URL> load(Class<?> serviceType) {
+ return load(serviceType, Collection.class.cast(Collections.emptySet()));
+ }
+
+ public Collection<URL> load(Class<?> serviceType, Collection<URL> configsLoaded) {
+ List<URL> result = new ArrayList<>();
+ try{
+ Enumeration<URL> resources = getClassLoader().getResources(PREFIX + serviceType.getName());
+ while(resources.hasMoreElements()){
+ URL res = resources.nextElement();
+ if(!configsLoaded.contains(res)){
+ result.add(res);
+ }
+ }
+ return result;
+ }
+ catch(Exception e){
+ fail(serviceType, "Failed to load service config: " + PREFIX+serviceType.getName(), e);
+ }
+ return result;
+ }
+
+
+
+ // Parse a single line from the given configuration file, adding the name
+ // on the line to the names list.
+ //
+ private int parseLine(Class<?> serviceType, URL u, BufferedReader r, int lc,
+ List<String> names)
+ throws IOException, ServiceConfigurationError {
+ String ln = r.readLine();
+ if (ln == null) {
+ return -1;
+ }
+ int ci = ln.indexOf('#');
+ if (ci >= 0) ln = ln.substring(0, ci);
+ ln = ln.trim();
+ int n = ln.length();
+ if (n != 0) {
+ if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
+ fail(serviceType, u, lc, "Illegal configuration-file syntax");
+ int cp = ln.codePointAt(0);
+ if (!Character.isJavaIdentifierStart(cp))
+ fail(serviceType, u, lc, "Illegal provider-class name: " + ln);
+ for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
+ cp = ln.codePointAt(i);
+ if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
+ fail(serviceType, u, lc, "Illegal provider-class name: " + ln);
+ }
+ Map<String, Object> services = this.servicesLoaded.get(serviceType);
+ if (services == null || !services.containsKey(ln) && !names.contains(ln))
+ names.add(ln);
+ }
+ return lc + 1;
+ }
+
+
+ // Parse the content of the given URL as a provider-configuration file.
+ //
+ // @param service
+ // The service type for which providers are being sought;
+ // used to construct error detail strings
+ //
+ // @param u
+ // The URL naming the configuration file to be parsed
+ //
+ // @return A (possibly empty) iterator that will yield the provider-class
+ // names in the given configuration file that are not yet members
+ // of the returned set
+ //
+ // @throws ServiceConfigurationError
+ // If an I/O error occurs while reading from the given URL, or
+ // if a configuration-file format error is detected
+ //
+ private Collection<String> parse(Class<?> service, URL u)
+ throws ServiceConfigurationError {
+ InputStream in = null;
+ BufferedReader r = null;
+ ArrayList<String> names = new ArrayList<>();
+ try {
+ in = u.openStream();
+ r = new BufferedReader(new InputStreamReader(in, "utf-8"));
+ int lc = 1;
+ while ((lc = parseLine(service, u, r, lc, names)) >= 0) ;
+ } catch (IOException x) {
+ fail(service, "Error reading configuration file", x);
+ } finally {
+ try {
+ if (r != null) r.close();
+ if (in != null) in.close();
+ } catch (IOException y) {
+ fail(service, "Error closing configuration file", y);
+ }
+ }
+ return names;
+ }
+
+
+ private static void fail(Class<?> service, String msg, Throwable cause)
+ throws ServiceConfigurationError {
+ LOG.log(Level.SEVERE, "Failed to load: " + service.getName() + ": " + msg, cause);
+ }
+
+ private static void fail(Class<?> service, String msg)
+ throws ServiceConfigurationError {
+ LOG.log(Level.SEVERE, "Failed to load: " + service.getName() + ": " + msg);
+ }
+
+ private static void fail(Class<?> service, URL u, int line, String msg)
+ throws ServiceConfigurationError {
+ fail(service, u + ":" + line + ": " + msg);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/459510e3/sandbox/classloader-support/src/main/resources/META-INF/services/org.apache.tamaya.spi.ServiceContext
----------------------------------------------------------------------
diff --git a/sandbox/classloader-support/src/main/resources/META-INF/services/org.apache.tamaya.spi.ServiceContext b/sandbox/classloader-support/src/main/resources/META-INF/services/org.apache.tamaya.spi.ServiceContext
new file mode 100644
index 0000000..c3b6acd
--- /dev/null
+++ b/sandbox/classloader-support/src/main/resources/META-INF/services/org.apache.tamaya.spi.ServiceContext
@@ -0,0 +1,19 @@
+#
+# 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 current 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.
+#
+org.apache.tamaya.clsupport.internal.CLAwareServiceContext