You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tamaya.apache.org by st...@apache.org on 2014/12/27 14:57:59 UTC
[15/34] incubator-tamaya git commit: first step: move all sources to
a 'dormant' directory
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java
new file mode 100644
index 0000000..10355ef
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesFormat.java
@@ -0,0 +1,61 @@
+/*
+ * 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.core.internal.format;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tamaya.core.resource.Resource;
+import org.apache.tamaya.core.properties.ConfigurationFormat;
+
+public class PropertiesFormat implements ConfigurationFormat{
+
+ private final static Logger LOG = Logger.getLogger(PropertiesFormat.class.getName());
+
+ @Override
+ public String getFormatName(){
+ return "properties";
+ }
+
+ @Override
+ public boolean isAccepted(Resource resource) {
+ String path = resource.getFilename();
+ return path != null && path.endsWith(".properties");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Map<String,String> readConfiguration(Resource resource) {
+ if (isAccepted(resource) && resource.exists()) {
+ try (InputStream is = resource.getInputStream()) {
+ Properties p = new Properties();
+ p.load(is);
+ return Map.class.cast(p);
+ } catch (Exception e) {
+ LOG.log(Level.FINEST, e, () -> "Failed to read config from resource: " + resource);
+ }
+ }
+ return Collections.emptyMap();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java
new file mode 100644
index 0000000..660c092
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/format/PropertiesXmlFormat.java
@@ -0,0 +1,62 @@
+/*
+ * 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.core.internal.format;
+
+import org.apache.tamaya.core.resource.Resource;
+import org.apache.tamaya.core.properties.ConfigurationFormat;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+public class PropertiesXmlFormat implements ConfigurationFormat{
+
+ private final static Logger LOG = Logger.getLogger(PropertiesXmlFormat.class.getName());
+
+ @Override
+ public String getFormatName(){
+ return "xml-properties";
+ }
+
+ @Override
+ public boolean isAccepted(Resource resource){
+ String path = resource.getFilename();
+ return path != null && path.endsWith(".xml");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Map<String,String> readConfiguration(Resource resource) {
+ if (isAccepted(resource) && resource.exists()) {
+ try (InputStream is = resource.getInputStream()) {
+ Properties p = new Properties();
+ p.loadFromXML(is);
+ return Map.class.cast(p);
+ } catch (Exception e) {
+ LOG.log(Level.FINEST, e, () -> "Failed to read config from resource: " + resource);
+ }
+ }
+ return Collections.emptyMap();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigChangeCallbackMethod.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigChangeCallbackMethod.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigChangeCallbackMethod.java
new file mode 100644
index 0000000..f929f8e
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigChangeCallbackMethod.java
@@ -0,0 +1,67 @@
+/*
+ * 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.core.internal.inject;
+
+import org.apache.tamaya.core.properties.PropertyChangeSet;
+import org.apache.tamaya.Configuration;
+
+import java.lang.reflect.Method;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This class holds a method object that is annotated to be a callback method to be called on configuration
+ * changes.
+ */
+public final class ConfigChangeCallbackMethod {
+
+ private static final Logger LOG = Logger.getLogger(ConfigChangeCallbackMethod.class.getName());
+
+ private Method callbackMethod;
+
+ public ConfigChangeCallbackMethod(Method callbackMethod) {
+ this.callbackMethod = Optional.of(callbackMethod).filter(
+ (m) -> void.class.equals(m.getReturnType()) &&
+ m.getParameterCount() == 1 &&
+ m.getParameterTypes()[0].equals(PropertyChangeSet.class)).get();
+ }
+
+ public Consumer<PropertyChangeSet> createConsumer(Object instance, Configuration... configurations){
+ // TODO consider also environment !
+ return event -> {
+ for(Configuration cfg:configurations){
+ if(event.getPropertySource().getName().equals(cfg.getName())){
+ return;
+ }
+ }
+ call(instance, event);
+ };
+ }
+
+ public void call(Object instance, PropertyChangeSet configChangeEvent) {
+ try {
+ callbackMethod.setAccessible(true);
+ callbackMethod.invoke(instance, configChangeEvent);
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, e, () -> "Error calling ConfigChange callback method " + callbackMethod.getDeclaringClass().getName() + '.' + callbackMethod.getName() + " on " + instance);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigTemplateInvocationHandler.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigTemplateInvocationHandler.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigTemplateInvocationHandler.java
new file mode 100644
index 0000000..ff2c309
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigTemplateInvocationHandler.java
@@ -0,0 +1,76 @@
+/*
+ * 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.core.internal.inject;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.core.internal.inject.ConfiguredType;
+import org.apache.tamaya.core.internal.inject.InjectionUtils;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+/**
+ * Invocation handler that handles request against a configuration template.
+ */
+public final class ConfigTemplateInvocationHandler implements InvocationHandler {
+
+ /*
+ TODO
+ the given method (in case of a template) can use different caching strategies:
+ 1) no caching (always evaluate the values completely) - slow.
+ 2) instance caching (a cache per instance).
+ 3) classloader caching...
+ 4) global shared cache.
+ */
+
+
+ /**
+ * Any overriding configurations.
+ */
+ private Configuration[] configurations;
+ /**
+ * The configured type.
+ */
+ private ConfiguredType type;
+
+ /**
+ * Creates a new handler instance.
+ * @param type the target type, not null.
+ * @param configurations overriding configurations to be used for evaluating the values for injection into {@code instance}, not null.
+ * If no such config is passed, the default configurationa provided by the current
+ * registered providers are used.
+ */
+ public ConfigTemplateInvocationHandler(Class<?> type, Configuration... configurations) {
+ this.configurations = Objects.requireNonNull(configurations).clone();
+ this.type = new ConfiguredType(Objects.requireNonNull(type));
+ if (!type.isInterface()) {
+ throw new IllegalArgumentException("Can only proxy interfaces as configuration templates.");
+ }
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if ("toString".equals(method.getName())) {
+ return "Configured Proxy -> " + this.type.getType().getName();
+ }
+ String configValue = InjectionUtils.getConfigValue(method, configurations);
+ return InjectionUtils.adaptValue(method, method.getReturnType(), configValue);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigurationInjector.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigurationInjector.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigurationInjector.java
new file mode 100644
index 0000000..8a51375
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfigurationInjector.java
@@ -0,0 +1,61 @@
+/*
+ * 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.core.internal.inject;
+
+import org.apache.tamaya.Configuration;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Simple injector singleton that also registers instances configured using weak references.
+ */
+@SuppressWarnings("rawtypes")
+public final class ConfigurationInjector {
+
+ private static final ConfigurationInjector INSTANCE = new ConfigurationInjector();
+
+ private Map<Class, ConfiguredType> configuredTypes = new ConcurrentHashMap<>();
+
+ /**
+ * Extract the configuration annotation config and registers it per class, for later reuse.
+ * @param type the type to be configured.
+ * @return the configured type registered.
+ */
+ public static ConfiguredType registerType(Class<?> type){
+ return INSTANCE.configuredTypes.computeIfAbsent(type, ConfiguredType::new);
+ }
+
+ /**
+ * Configured the current instance and reigsterd necessary listener to forward config change events as
+ * defined by the current annotations in place.
+ * @param instance the instance to be configured
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ */
+ public static void configure(Object instance, Configuration... configurations){
+ Class type = Objects.requireNonNull(instance).getClass();
+ ConfiguredType configuredType = registerType(type);
+ Objects.requireNonNull(configuredType).configure(instance, configurations);
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredField.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredField.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredField.java
new file mode 100644
index 0000000..51c3904
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredField.java
@@ -0,0 +1,126 @@
+/*
+ * 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.core.internal.inject;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.annotation.ConfiguredProperties;
+import org.apache.tamaya.annotation.ConfiguredProperty;
+import org.apache.tamaya.annotation.DefaultAreas;
+import org.apache.tamaya.core.internal.Utils;
+
+/**
+ * Small class that contains and manages all information anc access to a configured field and a concrete instance current
+ * it (referenced by a weak reference). It also implements all aspects current keys filtering, converting any applying the
+ * final keys by reflection.
+ */
+public class ConfiguredField {
+
+
+ /**
+ * The configured field instance.
+ */
+ private Field annotatedField;
+
+ /**
+ * Models a configured field and provides mechanisms for injection.
+ *
+ * @param field the field instance.
+ */
+ public ConfiguredField(Field field) {
+ Objects.requireNonNull(field);
+ this.annotatedField = field;
+ }
+
+ /**
+ * Evaluate the initial keys fromMap the configuration and applyChanges it to the field.
+ *
+ * @param target the target instance.
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ * @throws ConfigException if evaluation or conversion failed.
+ */
+ public void applyInitialValue(Object target, Configuration... configurations) throws ConfigException {
+ String configValue = InjectionUtils.getConfigValue(this.annotatedField, configurations);
+ applyValue(target, configValue, false, configurations);
+ }
+
+
+ /**
+ * This method reapplies a changed configuration keys to the field.
+ *
+ * @param target the target instance, not null.
+ * @param configValue the new keys to be applied, null will trigger the evaluation current the configured default keys.
+ * @param resolve set to true, if expression resolution should be applied on the keys passed.
+ * @throws ConfigException if the configuration required could not be resolved or converted.
+ */
+ public void applyValue(Object target, String configValue, boolean resolve, Configuration... configurations) throws ConfigException {
+ Objects.requireNonNull(target);
+ try {
+ if (resolve && configValue != null) {
+ // net step perform exression resolution, if any
+ configValue = Configuration.evaluateValue(configValue, configurations);
+ }
+ // Check for adapter/filter
+ Object value = InjectionUtils.adaptValue(this.annotatedField, this.annotatedField.getType(), configValue);
+ annotatedField.setAccessible(true);
+ annotatedField.set(target, value);
+ } catch (Exception e) {
+ throw new ConfigException("Failed to annotation configured field: " + this.annotatedField.getDeclaringClass()
+ .getName() + '.' + annotatedField.getName(), e);
+ }
+ }
+
+
+ /**
+ * This method checks if the given (qualified) configuration key is referenced fromMap this field.
+ * This is useful to determine, if a key changed in a configuration should trigger any change events
+ * on the related instances.
+ *
+ * @param key the (qualified) configuration key, not null.
+ * @return true, if the key is referenced.
+ */
+ public boolean matchesKey(String configName, String key) {
+ Collection<ConfiguredProperty> configuredProperties = Utils.getAnnotations(this.annotatedField, ConfiguredProperty.class,
+ ConfiguredProperties.class );
+ for(ConfiguredProperty prop: configuredProperties){
+ String currentName = prop.config().trim();
+ if(currentName.isEmpty()){
+ if(!"default".equals(configName)){
+ continue;
+ }
+ }
+ else if(!currentName.equals(configName)){
+ continue;
+ }
+ DefaultAreas areasAnnot = this.annotatedField.getDeclaringClass().getAnnotation(DefaultAreas.class);
+ List<String> keys = InjectionUtils.evaluateKeys(this.annotatedField, areasAnnot, prop);
+ if( keys.contains(key)){
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredSetterMethod.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredSetterMethod.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredSetterMethod.java
new file mode 100644
index 0000000..90497ae
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredSetterMethod.java
@@ -0,0 +1,136 @@
+/*
+ * 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.core.internal.inject;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import org.apache.tamaya.core.properties.PropertyChangeSet;
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.annotation.*;
+import org.apache.tamaya.core.internal.Utils;
+
+/**
+ * Small class that contains and manages all information and access to a configured field and a concrete instance current
+ * it (referenced by a weak reference). It also implements all aspects current keys filtering, conversions any applying the
+ * final keys by reflection.
+ */
+public class ConfiguredSetterMethod {
+
+ /**
+ * The configured field instance.
+ */
+ private Method setterMethod;
+
+ /**
+ * Models a configured field and provides mechanisms for injection.
+ *
+ * @param method the method instance.
+ */
+ public ConfiguredSetterMethod(Method method) {
+ this.setterMethod = Optional.of(method).filter(
+ (m) -> void.class.equals(m.getReturnType()) &&
+ m.getParameterCount() == 1).get();
+ }
+
+ public Consumer<PropertyChangeSet> createConsumer(Object instance, Configuration... configurations){
+ // TODO consider environment as well
+ return event -> {
+ for(Configuration cfg:configurations){
+ if(event.getPropertySource().getName().equals(cfg.getName())){
+ // ignore these changes, since this config is overridden.
+ return;
+ }
+ }
+ String configValue = InjectionUtils.getConfigValue(setterMethod, configurations);
+ applyValue(instance,configValue, false, configurations);
+ };
+ }
+
+
+ /**
+ * Evaluate the initial keys fromMap the configuration and applyChanges it to the field.
+ *
+ * @param target the target instance.
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ * @throws ConfigException if evaluation or conversion failed.
+ */
+ public void applyInitialValue(Object target, Configuration... configurations) throws ConfigException {
+ String configValue = InjectionUtils.getConfigValue(this.setterMethod, configurations);
+ applyValue(target, configValue, false, configurations);
+ }
+
+ /**
+ * This method reapplies a changed configuration keys to the field.
+ *
+ * @param target the target instance, not null.
+ * @param configValue the new keys to be applied, null will trigger the evaluation current the configured default keys.
+ * @param resolve set to true, if expression resolution should be applied on the keys passed.
+ * @throws org.apache.tamaya.ConfigException if the configuration required could not be resolved or converted.
+ */
+ public void applyValue(Object target, String configValue, boolean resolve, Configuration... configurations) throws ConfigException {
+ Objects.requireNonNull(target);
+ try {
+ if (resolve && configValue != null) {
+ // net step perform exression resolution, if any
+ configValue = Configuration.evaluateValue(configValue, configurations);
+ }
+ // Check for adapter/filter
+ Object value = InjectionUtils.adaptValue(this.setterMethod, this.setterMethod.getParameterTypes()[0], configValue);
+ setterMethod.setAccessible(true);
+ setterMethod.invoke(target, value);
+ } catch (Exception e) {
+ throw new ConfigException("Failed to annotation configured method: " + this.setterMethod.getDeclaringClass()
+ .getName() + '.' + setterMethod.getName(), e);
+ }
+ }
+
+
+
+ /**
+ * This method checks if the given (qualified) configuration key is referenced fromMap this field.
+ * This is useful to determine, if a key changed in a configuration should trigger any change events
+ * on the related instances.
+ *
+ * @param key the (qualified) configuration key, not null.
+ * @return true, if the key is referenced.
+ */
+ public boolean matchesKey(String key) {
+ DefaultAreas areasAnnot = this.setterMethod.getDeclaringClass().getAnnotation(DefaultAreas.class);
+ Collection<ConfiguredProperty> configuredProperties =
+ Utils.getAnnotations(this.setterMethod, ConfiguredProperty.class, ConfiguredProperties.class);
+ for(ConfiguredProperty prop: configuredProperties) {
+ if (InjectionUtils.evaluateKeys(this.setterMethod, areasAnnot, prop).contains(key)) {
+ return true;
+ }
+ }
+ if (InjectionUtils.evaluateKeys(this.setterMethod, areasAnnot).contains(key)) {
+ return true;
+ }
+ return false;
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredType.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredType.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredType.java
new file mode 100644
index 0000000..879d54a
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/ConfiguredType.java
@@ -0,0 +1,222 @@
+/*
+ * 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.core.internal.inject;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import org.apache.tamaya.core.properties.PropertyChangeSet;
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.PropertySource;
+import org.apache.tamaya.annotation.*;
+import org.apache.tamaya.core.internal.Utils;
+
+/**
+ * Structure that contains and manages configuration related things for a configured type registered.
+ * Created by Anatole on 03.10.2014.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class ConfiguredType {
+ /**
+ * A list with all annotated instance variables.
+ */
+ private List<ConfiguredField> configuredFields = new ArrayList<>();
+ /**
+ * A list with all annotated methods (templates).
+ */
+ private List<ConfiguredSetterMethod> configuredSetterMethods = new ArrayList<>();
+ /**
+ * A list with all callback methods listening to config changes.
+ */
+ private List<ConfigChangeCallbackMethod> callbackMethods = new ArrayList<>();
+ /**
+ * The basic type.
+ */
+ private Class type;
+
+ /**
+ * Creates an instance of this class hereby evaluating the config annotations given for later effective
+ * injection (configuration) of instances.
+ *
+ * @param type the instance type.
+ */
+
+ public ConfiguredType(Class type) {
+ this.type = Objects.requireNonNull(type);
+ initFields(type);
+ initMethods(type);
+ }
+
+ private void initFields(Class type) {
+ for (Field f : type.getDeclaredFields()) {
+ if (f.isAnnotationPresent(NoConfig.class)) {
+ continue;
+ }
+ try {
+ ConfiguredField configuredField = new ConfiguredField(f);
+ configuredFields.add(configuredField);
+ } catch (Exception e) {
+ throw new ConfigException("Failed to initialized configured field: " +
+ f.getDeclaringClass().getName() + '.' + f.getName(), e);
+ }
+ }
+ }
+
+ private void initMethods(Class type) {
+ // TODO revisit this logic here...
+ for (Method m : type.getDeclaredMethods()) {
+ if (m.isAnnotationPresent(NoConfig.class)) {
+ continue;
+ }
+ ObservesConfigChange mAnnot = m.getAnnotation(ObservesConfigChange.class);
+ Collection<ConfiguredProperty> propertiesAnnots = Utils.getAnnotations(m, ConfiguredProperty.class, ConfiguredProperties.class);
+ if (type.isInterface()) {
+ // it is a template
+ if (mAnnot != null) {
+ if (m.isDefault()) {
+ addObserverMethod(m);
+ }
+ } else {
+ if (m.isDefault()) {
+ addPropertySetter(m, propertiesAnnots);
+ }
+ }
+ } else {
+ if (mAnnot != null) {
+ addObserverMethod(m);
+ } else {
+ addPropertySetter(m, propertiesAnnots);
+ }
+ }
+ }
+ }
+
+ private boolean addPropertySetter(Method m, Collection<ConfiguredProperty> propertiesAnnots) {
+ if (!propertiesAnnots.isEmpty()) {
+ if (m.getParameterTypes().length == 0) {
+ // getter method
+ Class<?> returnType = m.getReturnType();
+ if (!void.class.equals(returnType)) {
+ try {
+ configuredSetterMethods.add(new ConfiguredSetterMethod(m));
+ return true;
+ } catch (Exception e) {
+ throw new ConfigException("Failed to initialized configured setter method: " +
+ m.getDeclaringClass().getName() + '.' + m.getName(), e);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+
+ private void addObserverMethod(Method m) {
+ if (m.getParameterTypes().length != 1) {
+ return;
+ }
+ if (!m.getParameterTypes()[0].equals(PropertyChangeSet.class)) {
+ return;
+ }
+ if (!void.class.equals(m.getReturnType())) {
+ return;
+ }
+ try {
+ this.callbackMethods.add(new ConfigChangeCallbackMethod(m));
+ } catch (Exception e) {
+ throw new ConfigException("Failed to initialized configured callback method: " +
+ m.getDeclaringClass().getName() + '.' + m.getName(), e);
+ }
+ }
+
+
+ /**
+ * Method called to configure an instance.
+ *
+ * @param instance The instance to be configured.
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ */
+ public void configure(Object instance, Configuration... configurations) {
+ for (ConfiguredField field : configuredFields) {
+ field.applyInitialValue(instance, configurations);
+ }
+ for (ConfiguredSetterMethod method : configuredSetterMethods) {
+ method.applyInitialValue(instance, configurations);
+ // TODO, if method should be recalled on changes, corresponding callbacks could be registered here
+ WeakConfigListenerManager.of().registerConsumer(instance, method.createConsumer(instance, configurations));
+ }
+ // Register callbacks for this intance (weakly)
+ for (ConfigChangeCallbackMethod callback : callbackMethods) {
+ WeakConfigListenerManager.of().registerConsumer(instance, callback.createConsumer(instance, configurations));
+ }
+ }
+
+
+ private String getName(Object source) {
+ if (source instanceof PropertySource) {
+ PropertySource ps = (PropertySource) source;
+ return ps.getName();
+ }
+ return "N/A";
+ }
+
+
+ public boolean isConfiguredBy(Configuration configuration) {
+ // TODO implement this
+ return true;
+ }
+
+ public static boolean isConfigured(Class type) {
+ if (type.getAnnotation(DefaultAreas.class) != null) {
+ return true;
+ }
+ // if no class level annotation is there we might have field level annotations only
+ for (Field field : type.getDeclaredFields()) {
+ if (field.isAnnotationPresent(ConfiguredProperties.class)) {
+ return true;
+ }
+ }
+ // if no class level annotation is there we might have method level annotations only
+ for (Method method : type.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(ConfiguredProperties.class)) {
+ return true;
+ }
+ }
+ for (Field field : type.getDeclaredFields()) {
+ if (field.isAnnotationPresent(ConfiguredProperty.class)) {
+ return true;
+ }
+ }
+ // if no class level annotation is there we might have method level annotations only
+ for (Method method : type.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(ConfiguredProperty.class)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Class getType() {
+ return this.type;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/InjectionUtils.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/InjectionUtils.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/InjectionUtils.java
new file mode 100644
index 0000000..d80ee80
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/InjectionUtils.java
@@ -0,0 +1,221 @@
+package org.apache.tamaya.core.internal.inject;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.tamaya.ConfigException;
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.PropertyAdapter;
+import org.apache.tamaya.annotation.*;
+import org.apache.tamaya.annotation.WithPropertyAdapter;
+import org.apache.tamaya.core.internal.Utils;
+import org.apache.tamaya.spi.PropertyAdapterSpi;
+
+/**
+ * Created by Anatole on 19.12.2014.
+ */
+@SuppressWarnings("unchecked")
+final class InjectionUtils {
+
+ private InjectionUtils(){}
+
+ /**
+ * This method evaluates the {@link org.apache.tamaya.Configuration} that currently is valid for the given target field/method.
+ *
+ * @return the {@link org.apache.tamaya.Configuration} instance to be used, never null.
+ */
+ public static Configuration getConfiguration(ConfiguredProperty prop, Configuration... configuration) {
+ String name = prop.config();
+ if (name != null && !name.trim().isEmpty()) {
+ return Configuration.current(name.trim());
+ }
+ return Configuration.current();
+ }
+
+ /**
+ * Evaluates all absolute configuration key based on the annotations found on a class.
+ *
+ * @param areasAnnot the (optional) annotation definining areas to be looked up.
+ * @param propertyAnnotation the annotation on field/method level that may defined one or
+ * several keys to be looked up (in absolute or relative form).
+ * @return the list current keys in order how they should be processed/looked up.
+ */
+ public static List<String> evaluateKeys(Member member, DefaultAreas areasAnnot, ConfiguredProperty propertyAnnotation) {
+ List<String> keys = new ArrayList<>(Arrays.asList(propertyAnnotation.keys()));
+ if (keys.isEmpty()) //noinspection UnusedAssignment
+ keys.add(member.getName());
+ ListIterator<String> iterator = keys.listIterator();
+ while (iterator.hasNext()) {
+ String next = iterator.next();
+ if (next.startsWith("[") && next.endsWith("]")) {
+ // absolute key, strip away brackets, take key as is
+ iterator.set(next.substring(1, next.length() - 1));
+ } else {
+ if (areasAnnot != null) {
+ // Remove original entry, since it will be replaced with prefixed entries
+ iterator.remove();
+ // Add prefixed entries, including absolute (root) entry for "" area keys.
+ for (String area : areasAnnot.value()) {
+ iterator.add(area.isEmpty() ? next : area + '.' + next);
+ }
+ }
+ }
+ }
+ return keys;
+ }
+
+ /**
+ * Evaluates all absolute configuration key based on the member name found.
+ *
+ * @param areasAnnot the (optional) annotation definining areas to be looked up.
+ * @return the list current keys in order how they should be processed/looked up.
+ */
+ public static List<String> evaluateKeys(Member member, DefaultAreas areasAnnot) {
+ List<String> keys = new ArrayList<>();
+ String name = member.getName();
+ String mainKey;
+ if(name.startsWith("get") || name.startsWith("set")){
+ mainKey = Character.toLowerCase(name.charAt(3)) + name.substring(4);
+ }
+ else{
+ mainKey = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ }
+ keys.add(mainKey);
+ if (areasAnnot != null) {
+ // Add prefixed entries, including absolute (root) entry for "" area keys.
+ for (String area : areasAnnot.value()) {
+ if(!area.isEmpty()) {
+ keys.add(area + '.' + mainKey);
+ }
+ }
+ }
+ else{ // add package name
+ keys.add(member.getDeclaringClass().getName()+'.'+mainKey);
+ }
+ return keys;
+ }
+
+ /**
+ * Internally evaluated the current valid configuration keys based on the given annotations present.
+ *
+ * @return the keys to be returned, or null.
+ */
+ public static String getConfigValue(Method method, Configuration... configurations) {
+ DefaultAreas areasAnnot = method.getDeclaringClass().getAnnotation(DefaultAreas.class);
+ WithLoadPolicy loadPolicy = Utils.getAnnotation(WithLoadPolicy.class, method, method.getDeclaringClass());
+ return getConfigValueInternal(method, areasAnnot, loadPolicy, configurations);
+ }
+
+
+ /**
+ * Internally evaluated the current valid configuration keys based on the given annotations present.
+ *
+ * @return the keys to be returned, or null.
+ */
+ public static String getConfigValue(Field field, Configuration... configurations) {
+ DefaultAreas areasAnnot = field.getDeclaringClass().getAnnotation(DefaultAreas.class);
+ WithLoadPolicy loadPolicy = Utils.getAnnotation(WithLoadPolicy.class, field, field.getDeclaringClass());
+ return getConfigValueInternal(field, areasAnnot, loadPolicy, configurations);
+ }
+
+ /**
+ * Internally evaluated the current valid configuration keys based on the given annotations present.
+ *
+ * @return the keys to be returned, or null.
+ */
+ private static String getConfigValueInternal(AnnotatedElement element, DefaultAreas areasAnnot, WithLoadPolicy loadPolicy, Configuration... configurations) {
+ Collection<ConfiguredProperty> configuredProperties = Utils.getAnnotations(
+ element, ConfiguredProperty.class, ConfiguredProperties.class);
+ DefaultValue defaultAnnot = element.getAnnotation(DefaultValue.class);
+ String configValue = null;
+ if(configuredProperties.isEmpty()){
+ List<String> keys = InjectionUtils.evaluateKeys((Member)element, areasAnnot);
+ Configuration config = InjectionUtils.getConfiguration("default", configurations);
+ configValue = evaluteConfigValue(configValue, keys, config);
+ }
+ else {
+ for (ConfiguredProperty prop : configuredProperties) {
+ List<String> keys = InjectionUtils.evaluateKeys((Member) element, areasAnnot, prop);
+ Configuration config = InjectionUtils.getConfiguration(prop, configurations);
+ configValue = evaluteConfigValue(configValue, keys, config);
+ }
+ }
+ if (configValue == null && defaultAnnot != null) {
+ return defaultAnnot.value();
+ }
+ return configValue;
+ }
+
+ private static String evaluteConfigValue(String configValue, List<String> keys, Configuration config) {
+ for (String key : keys) {
+ configValue = config.get(key).orElse(null);
+ if (configValue != null) {
+ break;
+ }
+ }
+ if (configValue != null) {
+ // net step perform expression resolution, if any
+ configValue = Configuration.evaluateValue(configValue, config);
+ }
+ return configValue;
+ }
+
+
+ @SuppressWarnings("rawtypes")
+ public static <T> T adaptValue(AnnotatedElement element, Class<T> targetType, String configValue){
+ try {
+ // Check for adapter/filter
+// T adaptedValue = null;
+ WithPropertyAdapter codecAnnot = element.getAnnotation(WithPropertyAdapter.class);
+ Class<? extends PropertyAdapter> codecType;
+ if (codecAnnot != null) {
+ codecType = codecAnnot.value();
+ if (!codecType.equals(PropertyAdapter.class)) {
+ // TODO cache here...
+// Codec<String> codec = codecType.newInstance();
+// adaptedValue = (T) codec.adapt(configValue);
+ }
+ }
+ if (String.class.equals(targetType)) {
+ return (T)configValue;
+ } else {
+ PropertyAdapter<?> adapter = PropertyAdapter.getInstance(targetType);
+ return (T)adapter.adapt(configValue);
+ }
+ } catch (Exception e) {
+ throw new ConfigException("Failed to annotate configured member: " + element, e);
+ }
+ }
+
+ /**
+ * This method evaluates the {@link Configuration} that currently is valid for the given target field/method.
+ * @param configurations Configuration instances that replace configuration served by services. This allows
+ * more easily testing and adaption.
+ * @return the {@link Configuration} instance to be used, never null.
+ */
+ public static Configuration getConfiguration(String name, Configuration... configurations) {
+ if(name!=null) {
+ for(Configuration conf: configurations){
+ if(name.equals(conf.getName())){
+ return conf;
+ }
+ }
+ return Configuration.current(name);
+ }
+ else{
+ for(Configuration conf: configurations){
+ if("default".equals(conf.getName())){
+ return conf;
+ }
+ }
+ }
+ return Configuration.current();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/WeakConfigListenerManager.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/WeakConfigListenerManager.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/WeakConfigListenerManager.java
new file mode 100644
index 0000000..e9b9ec3
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/inject/WeakConfigListenerManager.java
@@ -0,0 +1,117 @@
+/*
+ * 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.core.internal.inject;
+
+import org.apache.tamaya.core.properties.PropertyChangeSet;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.StampedLock;
+import java.util.function.Consumer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Simple listener container that only holds weak references on the listeners.
+ */
+public final class WeakConfigListenerManager{
+
+ private static final WeakConfigListenerManager INSTANCE = new WeakConfigListenerManager();
+
+ private static final Logger LOG = Logger.getLogger(WeakConfigListenerManager.class.getName());
+ private StampedLock lock = new StampedLock();
+ private Map<Object,Consumer<PropertyChangeSet>> listenerReferences = new WeakHashMap<>();
+
+ /** Private singleton constructor. */
+ private WeakConfigListenerManager(){}
+
+ public static WeakConfigListenerManager of(){
+ return INSTANCE;
+ }
+
+ /**
+ * Registers the given consumer for the instance. If a consumer already exists for this instance the given
+ * consumer is appended.
+ * @param instance the instance, not null.
+ * @param listener the consumer.
+ */
+ public void registerConsumer(Object instance, Consumer<PropertyChangeSet> listener){
+ Lock writeLock = lock.asWriteLock();
+ try {
+ writeLock.lock();
+ Consumer<PropertyChangeSet> l = listenerReferences.get(instance);
+ if (l == null) {
+ listenerReferences.put(instance, listener);
+ } else {
+ listenerReferences.put(instance, l.andThen(listener));
+ }
+ }
+ finally{
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Unregisters all consumers for the given instance.
+ * @param instance the instance, not null.
+ */
+ public void unregisterConsumer(Object instance) {
+ Lock writeLock = lock.asWriteLock();
+ try {
+ writeLock.lock();
+ listenerReferences.remove(instance);
+ }
+ finally{
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * Publishes a change event to all consumers registered.
+ * @param change the change event, not null.
+ */
+ public void publishChangeEvent(PropertyChangeSet change){
+ Lock readLock = lock.asReadLock();
+ try{
+ readLock.lock();
+ listenerReferences.values().parallelStream().forEach(l -> {
+ try{
+ l.accept(change);
+ }
+ catch(Exception e){
+ LOG.log(Level.SEVERE, "ConfigChangeListener failed: " + l.getClass().getName(), e);
+ }
+ });
+ }
+ finally{
+ readLock.unlock();
+ }
+ }
+
+
+ @Override
+ public String toString(){
+ return "WeakConfigListenerManager{" +
+ "listenerReferences=" + listenerReferences +
+ '}';
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/AbstractDelegatingLogger.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/AbstractDelegatingLogger.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/AbstractDelegatingLogger.java
new file mode 100644
index 0000000..cc0ac45
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/AbstractDelegatingLogger.java
@@ -0,0 +1,411 @@
+/*
+ * 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.core.internal.logging;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.logging.*;
+
+/**
+ * java.util.logging.Logger implementation delegating to another framework.
+ * All methods can be used except:
+ * setLevel
+ * addHandler / getHandlers
+ * setParent / getParent
+ * setUseParentHandlers / getUseParentHandlers
+ *
+ * @author gnodet
+ */
+public abstract class AbstractDelegatingLogger extends Logger {
+
+ protected AbstractDelegatingLogger(final String name, final String resourceBundleName) {
+ super(name, resourceBundleName);
+ }
+
+ public void log(final LogRecord record) {
+ if (isLoggable(record.getLevel())) {
+ doLog(record);
+ }
+ }
+
+ public void log(final Level level, final String msg) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ doLog(lr);
+ }
+ }
+
+ public void log(final Level level, final String msg, final Object param1) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ final Object[] params = {param1};
+ lr.setParameters(params);
+ doLog(lr);
+ }
+ }
+
+ public void log(final Level level, final String msg, final Object[] params) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setParameters(params);
+ doLog(lr);
+ }
+ }
+
+ public void log(final Level level, final String msg, final Throwable thrown) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setThrown(thrown);
+ doLog(lr);
+ }
+ }
+
+ public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ doLog(lr);
+ }
+ }
+
+ public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg, final Object param1) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ final Object[] params = {param1};
+ lr.setParameters(params);
+ doLog(lr);
+ }
+ }
+
+ public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg, final Object[] params) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ lr.setParameters(params);
+ doLog(lr);
+ }
+ }
+
+ public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg, final Throwable thrown) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ lr.setThrown(thrown);
+ doLog(lr);
+ }
+ }
+
+ public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName, final String msg) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ doLog(lr, bundleName);
+ }
+ }
+
+ public void logrb(final Level level, final String sourceClass, final String sourceMethod,
+ final String bundleName, final String msg, final Object param1) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ final Object[] params = {param1};
+ lr.setParameters(params);
+ doLog(lr, bundleName);
+ }
+ }
+
+ public void logrb(final Level level, final String sourceClass, final String sourceMethod,
+ final String bundleName, final String msg, final Object[] params) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ lr.setParameters(params);
+ doLog(lr, bundleName);
+ }
+ }
+
+ public void logrb(final Level level, final String sourceClass, final String sourceMethod,
+ final String bundleName, final String msg, final Throwable thrown) {
+ if (isLoggable(level)) {
+ final LogRecord lr = new LogRecord(level, msg);
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ lr.setThrown(thrown);
+ doLog(lr, bundleName);
+ }
+ }
+
+ public void entering(final String sourceClass, final String sourceMethod) {
+ if (isLoggable(Level.FINER)) {
+ logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
+ }
+ }
+
+ public void entering(final String sourceClass, final String sourceMethod, final Object param1) {
+ if (isLoggable(Level.FINER)) {
+ final Object[] params = {param1};
+ logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params);
+ }
+ }
+
+ public void entering(final String sourceClass, final String sourceMethod, final Object[] params) {
+ if (isLoggable(Level.FINER)) {
+ final String msg = "ENTRY";
+ if (params == null) {
+ logp(Level.FINER, sourceClass, sourceMethod, msg);
+ return;
+ }
+ final StringBuilder builder = new StringBuilder(msg);
+ for (int i = 0; i < params.length; i++) {
+ builder.append(" {");
+ builder.append(Integer.toString(i));
+ builder.append("}");
+ }
+ logp(Level.FINER, sourceClass, sourceMethod, builder.toString(), params);
+ }
+ }
+
+ public void exiting(final String sourceClass, final String sourceMethod) {
+ if (isLoggable(Level.FINER)) {
+ logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
+ }
+ }
+
+ public void exiting(final String sourceClass, final String sourceMethod, final Object result) {
+ if (isLoggable(Level.FINER)) {
+ final Object[] params = {result};
+ logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", params);
+ }
+ }
+
+ public void throwing(final String sourceClass, final String sourceMethod, final Throwable thrown) {
+ if (isLoggable(Level.FINER)) {
+ final LogRecord lr = new LogRecord(Level.FINER, "THROW");
+ lr.setSourceClassName(sourceClass);
+ lr.setSourceMethodName(sourceMethod);
+ lr.setThrown(thrown);
+ doLog(lr);
+ }
+ }
+
+ public void severe(final String msg) {
+ if (isLoggable(Level.SEVERE)) {
+ final LogRecord lr = new LogRecord(Level.SEVERE, msg);
+ doLog(lr);
+ }
+ }
+
+ public void warning(final String msg) {
+ if (isLoggable(Level.WARNING)) {
+ final LogRecord lr = new LogRecord(Level.WARNING, msg);
+ doLog(lr);
+ }
+ }
+
+ public void info(final String msg) {
+ if (isLoggable(Level.INFO)) {
+ final LogRecord lr = new LogRecord(Level.INFO, msg);
+ doLog(lr);
+ }
+ }
+
+ public void config(final String msg) {
+ if (isLoggable(Level.CONFIG)) {
+ final LogRecord lr = new LogRecord(Level.CONFIG, msg);
+ doLog(lr);
+ }
+ }
+
+ public void fine(final String msg) {
+ if (isLoggable(Level.FINE)) {
+ final LogRecord lr = new LogRecord(Level.FINE, msg);
+ doLog(lr);
+ }
+ }
+
+ public void finer(final String msg) {
+ if (isLoggable(Level.FINER)) {
+ final LogRecord lr = new LogRecord(Level.FINER, msg);
+ doLog(lr);
+ }
+ }
+
+ public void finest(final String msg) {
+ if (isLoggable(Level.FINEST)) {
+ final LogRecord lr = new LogRecord(Level.FINEST, msg);
+ doLog(lr);
+ }
+ }
+
+ public void setLevel(final Level newLevel) throws SecurityException {
+ throw new UnsupportedOperationException();
+ }
+
+ public abstract Level getLevel();
+
+ public boolean isLoggable(final Level level) {
+ final Level l = getLevel();
+ return level.intValue() >= l.intValue() && l != Level.OFF;
+ }
+
+ protected boolean supportsHandlers() {
+ return false;
+ }
+
+ public synchronized void addHandler(final Handler handler) throws SecurityException {
+ if (supportsHandlers()) {
+ super.addHandler(handler);
+ return;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized void removeHandler(final Handler handler) throws SecurityException {
+ if (supportsHandlers()) {
+ super.removeHandler(handler);
+ return;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized Handler[] getHandlers() {
+ if (supportsHandlers()) {
+ return super.getHandlers();
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized void setUseParentHandlers(final boolean useParentHandlers) {
+ if (supportsHandlers()) {
+ super.setUseParentHandlers(useParentHandlers);
+ return;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized boolean getUseParentHandlers() {
+ if (supportsHandlers()) {
+ return super.getUseParentHandlers();
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ public Logger getParent() {
+ return null;
+ }
+
+ public void setParent(final Logger parent) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected void doLog(final LogRecord lr) {
+ lr.setLoggerName(getName());
+ final String rbname = getResourceBundleName();
+ if (rbname != null) {
+ lr.setResourceBundleName(rbname);
+ lr.setResourceBundle(getResourceBundle());
+ }
+ internalLog(lr);
+ }
+
+ protected void doLog(final LogRecord lr, final String rbname) {
+ lr.setLoggerName(getName());
+ if (rbname != null) {
+ lr.setResourceBundleName(rbname);
+ lr.setResourceBundle(loadResourceBundle(rbname));
+ }
+ internalLog(lr);
+ }
+
+ protected void internalLog(final LogRecord record) {
+ final Filter filter = getFilter();
+ if (filter != null && !filter.isLoggable(record)) {
+ return;
+ }
+ final String msg = formatMessage(record);
+ internalLogFormatted(msg, record);
+ }
+
+ protected abstract void internalLogFormatted(String msg, LogRecord record);
+
+ protected String formatMessage(final LogRecord record) {
+ String format = record.getMessage();
+ final ResourceBundle catalog = record.getResourceBundle();
+ if (catalog != null) {
+ try {
+ format = catalog.getString(record.getMessage());
+ } catch (final MissingResourceException ex) {
+ format = record.getMessage();
+ }
+ }
+ try {
+ final Object[] parameters = record.getParameters();
+ if (parameters == null || parameters.length == 0) {
+ return format;
+ }
+ if (format.contains("{0") || format.contains("{1")
+ || format.contains("{2") || format.contains("{3")) {
+ return MessageFormat.format(format, parameters);
+ }
+ return format;
+ } catch (final Exception ex) {
+ return format;
+ }
+ }
+
+ /**
+ * Load the specified resource bundle
+ *
+ * @param resourceBundleName the name current the resource bundle to load, cannot be null
+ * @return the loaded resource bundle.
+ * @throws MissingResourceException If the specified resource bundle can not be loaded.
+ */
+ static ResourceBundle loadResourceBundle(final String resourceBundleName) {
+ // try context class loader to load the resource
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ if (null != cl) {
+ try {
+ return ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), cl);
+ } catch (final MissingResourceException e) {
+ // Failed to load using context classloader, ignore
+ }
+ }
+ // try system class loader to load the resource
+ cl = ClassLoader.getSystemClassLoader();
+ if (null != cl) {
+ try {
+ return ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), cl);
+ } catch (final MissingResourceException e) {
+ // Failed to load using system classloader, ignore
+ }
+ }
+ return null;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Log4j2Logger.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Log4j2Logger.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Log4j2Logger.java
new file mode 100644
index 0000000..35ae4ab
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Log4j2Logger.java
@@ -0,0 +1,97 @@
+/*
+ * 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.core.internal.logging;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+public class Log4j2Logger extends AbstractDelegatingLogger {
+ private static final Map<Level, org.apache.logging.log4j.Level> TO_LOG4J = new HashMap<>();
+
+ private final Logger log;
+
+ static {
+ //older versions current log4j don't have TRACE, use debug
+// org.apache.logging.log4j.Level t = org.apache.logging.log4j.Level.DEBUG;
+
+ TO_LOG4J.put(Level.ALL, org.apache.logging.log4j.Level.ALL);
+ TO_LOG4J.put(Level.SEVERE, org.apache.logging.log4j.Level.ERROR);
+ TO_LOG4J.put(Level.WARNING, org.apache.logging.log4j.Level.WARN);
+ TO_LOG4J.put(Level.INFO, org.apache.logging.log4j.Level.INFO);
+ TO_LOG4J.put(Level.CONFIG, org.apache.logging.log4j.Level.DEBUG);
+ TO_LOG4J.put(Level.FINE, org.apache.logging.log4j.Level.DEBUG);
+ TO_LOG4J.put(Level.FINER, org.apache.logging.log4j.Level.TRACE);
+ TO_LOG4J.put(Level.FINEST, org.apache.logging.log4j.Level.TRACE);
+ TO_LOG4J.put(Level.OFF, org.apache.logging.log4j.Level.OFF);
+ }
+
+ public Log4j2Logger(final String name, final String resourceBundleName) {
+ super(name, resourceBundleName);
+ log = LogManager.getLogger(name);
+ }
+
+ public Level getLevel() {
+ final org.apache.logging.log4j.Level l = log.getLevel();
+ if (l != null) {
+ return fromL4J(l);
+ }
+ return null;
+ }
+
+ protected void internalLogFormatted(final String msg, final LogRecord record) {
+ log.log(TO_LOG4J.get(record.getLevel()), msg, record.getThrown());
+ }
+
+
+ private Level fromL4J(final org.apache.logging.log4j.Level l) {
+ Level l2 = null;
+ switch (l.getStandardLevel()) {
+ case ALL:
+ l2 = Level.ALL;
+ break;
+ case FATAL:
+ l2 = Level.SEVERE;
+ break;
+ case ERROR:
+ l2 = Level.SEVERE;
+ break;
+ case WARN:
+ l2 = Level.WARNING;
+ break;
+ case INFO:
+ l2 = Level.INFO;
+ break;
+ case DEBUG:
+ l2 = Level.FINE;
+ break;
+ case OFF:
+ l2 = Level.OFF;
+ break;
+ case TRACE:
+ l2 = Level.FINEST;
+ break;
+ default:
+ l2 = Level.FINE;
+ }
+ return l2;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Log4jLogger.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Log4jLogger.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Log4jLogger.java
new file mode 100644
index 0000000..224378c
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Log4jLogger.java
@@ -0,0 +1,200 @@
+/*
+ * 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.core.internal.logging;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.Priority;
+import org.apache.log4j.spi.LoggingEvent;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * java.util.logging.Logger implementation delegating to Log4j.
+ * All methods can be used except:
+ * setLevel
+ * addHandler / getHandlers
+ * setParent / getParent
+ * setUseParentHandlers / getUseParentHandlers
+ *
+ * @author gnodet
+ */
+public class Log4jLogger extends AbstractDelegatingLogger {
+ private static final Map<Level, org.apache.log4j.Level> TO_LOG4J = new HashMap<>();
+ private static final org.apache.log4j.Level TRACE;
+
+ private final Logger log;
+
+ static {
+ //older versions current log4j don't have TRACE, use debug
+ org.apache.log4j.Level t = org.apache.log4j.Level.DEBUG;
+ try {
+ final Field f = org.apache.log4j.Level.class.getField("TRACE");
+ t = (org.apache.log4j.Level) f.get(null);
+ } catch (final Throwable ex) {
+ //ignore, assume old version current log4j
+ }
+ TRACE = t;
+
+ TO_LOG4J.put(Level.ALL, org.apache.log4j.Level.ALL);
+ TO_LOG4J.put(Level.SEVERE, org.apache.log4j.Level.ERROR);
+ TO_LOG4J.put(Level.WARNING, org.apache.log4j.Level.WARN);
+ TO_LOG4J.put(Level.INFO, org.apache.log4j.Level.INFO);
+ TO_LOG4J.put(Level.CONFIG, org.apache.log4j.Level.DEBUG);
+ TO_LOG4J.put(Level.FINE, org.apache.log4j.Level.DEBUG);
+ TO_LOG4J.put(Level.FINER, TRACE);
+ TO_LOG4J.put(Level.FINEST, TRACE);
+ TO_LOG4J.put(Level.OFF, org.apache.log4j.Level.OFF);
+ }
+
+ public Log4jLogger(final String name, final String resourceBundleName) {
+ super(name, resourceBundleName);
+ log = LogManager.getLogger(name);
+ }
+
+ public Level getLevel() {
+ final org.apache.log4j.Level l = log.getEffectiveLevel();
+ if (l != null) {
+ return fromL4J(l);
+ }
+ return null;
+ }
+
+ public void setLevel(final Level newLevel) throws SecurityException {
+ log.setLevel(TO_LOG4J.get(newLevel));
+ }
+
+ public synchronized void addHandler(final Handler handler) throws SecurityException {
+ log.addAppender(new HandlerWrapper(handler));
+ }
+
+ public synchronized void removeHandler(final Handler handler) throws SecurityException {
+ log.removeAppender("HandlerWrapper-" + handler.hashCode());
+ }
+
+ public synchronized Handler[] getHandlers() {
+ final List<Handler> ret = new ArrayList<>();
+ final Enumeration<?> en = log.getAllAppenders();
+ while (en.hasMoreElements()) {
+ final Appender ap = (Appender) en.nextElement();
+ if (ap instanceof HandlerWrapper) {
+ ret.add(((HandlerWrapper) ap).getHandler());
+ }
+ }
+ return ret.toArray(new Handler[ret.size()]);
+ }
+
+ protected void internalLogFormatted(final String msg, final LogRecord record) {
+ log.log(AbstractDelegatingLogger.class.getName(),
+ TO_LOG4J.get(record.getLevel()),
+ msg,
+ record.getThrown());
+ }
+
+
+ private Level fromL4J(final org.apache.log4j.Level l) {
+ Level l2 = null;
+ switch (l.toInt()) {
+ case org.apache.log4j.Level.ALL_INT:
+ l2 = Level.ALL;
+ break;
+ case org.apache.log4j.Level.FATAL_INT:
+ l2 = Level.SEVERE;
+ break;
+ case org.apache.log4j.Level.ERROR_INT:
+ l2 = Level.SEVERE;
+ break;
+ case org.apache.log4j.Level.WARN_INT:
+ l2 = Level.WARNING;
+ break;
+ case org.apache.log4j.Level.INFO_INT:
+ l2 = Level.INFO;
+ break;
+ case org.apache.log4j.Level.DEBUG_INT:
+ l2 = Level.FINE;
+ break;
+ case org.apache.log4j.Level.OFF_INT:
+ l2 = Level.OFF;
+ break;
+ default:
+ if (l.toInt() == TRACE.toInt()) {
+ l2 = Level.FINEST;
+ }
+ }
+ return l2;
+ }
+
+
+ private class HandlerWrapper extends AppenderSkeleton {
+ Handler handler;
+
+ public HandlerWrapper(final Handler h) {
+ handler = h;
+ name = "HandlerWrapper-" + h.hashCode();
+ }
+
+ public Handler getHandler() {
+ return handler;
+ }
+
+ @Override
+ protected void append(final LoggingEvent event) {
+ final LogRecord lr = new LogRecord(fromL4J(event.getLevel()),
+ event.getMessage().toString());
+ lr.setLoggerName(event.getLoggerName());
+ if (event.getThrowableInformation() != null) {
+ lr.setThrown(event.getThrowableInformation().getThrowable());
+ }
+ final String rbname = getResourceBundleName();
+ if (rbname != null) {
+ lr.setResourceBundleName(rbname);
+ lr.setResourceBundle(getResourceBundle());
+ }
+ handler.publish(lr);
+ }
+
+ public void close() {
+ handler.close();
+ closed = true;
+ }
+
+ public boolean requiresLayout() {
+ return false;
+ }
+
+ @Override
+ public Priority getThreshold() {
+ return TO_LOG4J.get(handler.getLevel());
+ }
+
+ @Override
+ public boolean isAsSevereAsThreshold(final Priority priority) {
+ final Priority p = getThreshold();
+ return p == null || priority.isGreaterOrEqual(p);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Slf4jLogger.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Slf4jLogger.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Slf4jLogger.java
new file mode 100644
index 0000000..a580128
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/logging/Slf4jLogger.java
@@ -0,0 +1,181 @@
+/*
+ * 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.core.internal.logging;
+
+import org.slf4j.spi.LocationAwareLogger;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * <p>
+ * java.util.logging.Logger implementation delegating to SLF4J.
+ * </p>
+ * <p>
+ * Methods {@link java.util.logging.Logger#setParent(Logger)}, {@link java.util.logging.Logger#getParent()},
+ * {@link java.util.logging.Logger#setUseParentHandlers(boolean)} and
+ * {@link java.util.logging.Logger#getUseParentHandlers()} are not overrriden.
+ * </p>
+ * <p>
+ * Level annotation inspired by {@link org.slf4j.bridge.SLF4JBridgeHandler}:
+ * </p>
+ * <p/>
+ * <pre>
+ * FINEST -> TRACE
+ * FINER -> DEBUG
+ * FINE -> DEBUG
+ * CONFIG -> DEBUG
+ * INFO -> INFO
+ * WARN ING -> WARN
+ * SEVER -> ERROR
+ * </pre>
+ */
+public class Slf4jLogger extends AbstractDelegatingLogger {
+
+ private static final String FQCN = AbstractDelegatingLogger.class.getName();
+
+ private final org.slf4j.Logger logger;
+ private LocationAwareLogger locationAwareLogger;
+
+
+ public Slf4jLogger(final String name, final String resourceBundleName) {
+ super(name, resourceBundleName);
+ logger = org.slf4j.LoggerFactory.getLogger(name);
+ if (logger instanceof LocationAwareLogger) {
+ locationAwareLogger = (LocationAwareLogger) logger;
+ }
+ }
+
+ @Override
+ protected boolean supportsHandlers() {
+ return true;
+ }
+
+ @Override
+ public Level getLevel() {
+ final Level level;
+ // Verify fromMap the wider (trace) to the narrower (error)
+ if (logger.isTraceEnabled()) {
+ level = Level.FINEST;
+ } else if (logger.isDebugEnabled()) {
+ // map to the lowest between FINER, FINE and CONFIG
+ level = Level.FINER;
+ } else if (logger.isInfoEnabled()) {
+ level = Level.INFO;
+ } else if (logger.isWarnEnabled()) {
+ level = Level.WARNING;
+ } else if (logger.isErrorEnabled()) {
+ level = Level.SEVERE;
+ } else {
+ level = Level.OFF;
+ }
+ return level;
+ }
+
+ @Override
+ public boolean isLoggable(final Level level) {
+ final int i = level.intValue();
+ if (i == Level.OFF.intValue()) {
+ return false;
+ } else if (i >= Level.SEVERE.intValue()) {
+ return logger.isErrorEnabled();
+ } else if (i >= Level.WARNING.intValue()) {
+ return logger.isWarnEnabled();
+ } else if (i >= Level.INFO.intValue()) {
+ return logger.isInfoEnabled();
+ } else if (i >= Level.FINER.intValue()) {
+ return logger.isDebugEnabled();
+ }
+ return logger.isTraceEnabled();
+ }
+
+
+ @Override
+ protected void internalLogFormatted(final String msg, final LogRecord record) {
+
+ final Level level = record.getLevel();
+ final Throwable t = record.getThrown();
+
+ final Handler[] targets = getHandlers();
+ if (targets != null) {
+ for (final Handler h : targets) {
+ h.publish(record);
+ }
+ }
+ if (!getUseParentHandlers()) {
+ return;
+ }
+
+ /*
+ * As we can not use a "switch ... case" block but only a "if ... else if ..." block, the order current the
+ * comparisons is important. We first try log level FINE then INFO, WARN, FINER, etc
+ */
+ if (Level.FINE.equals(level)) {
+ if (locationAwareLogger == null) {
+ logger.debug(msg, t);
+ } else {
+ locationAwareLogger.log(null, FQCN, LocationAwareLogger.DEBUG_INT, msg, null, t);
+ }
+ } else if (Level.INFO.equals(level)) {
+ if (locationAwareLogger == null) {
+ logger.info(msg, t);
+ } else {
+ locationAwareLogger.log(null, FQCN, LocationAwareLogger.INFO_INT, msg, null, t);
+ }
+ } else if (Level.WARNING.equals(level)) {
+ if (locationAwareLogger == null) {
+ logger.warn(msg, t);
+ } else {
+ locationAwareLogger.log(null, FQCN, LocationAwareLogger.WARN_INT, msg, null, t);
+ }
+ } else if (Level.FINER.equals(level)) {
+ if (locationAwareLogger == null) {
+ logger.trace(msg, t);
+ } else {
+ locationAwareLogger.log(null, FQCN, LocationAwareLogger.DEBUG_INT, msg, null, t);
+ }
+ } else if (Level.FINEST.equals(level)) {
+ if (locationAwareLogger == null) {
+ logger.trace(msg, t);
+ } else {
+ locationAwareLogger.log(null, FQCN, LocationAwareLogger.TRACE_INT, msg, null, t);
+ }
+ } else if (Level.ALL.equals(level)) {
+ // should never occur, all is used to configure java.util.logging
+ // but not accessible by the API Logger.xxx() API
+ if (locationAwareLogger == null) {
+ logger.error(msg, t);
+ } else {
+ locationAwareLogger.log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, null, t);
+ }
+ } else if (Level.SEVERE.equals(level)) {
+ if (locationAwareLogger == null) {
+ logger.error(msg, t);
+ } else {
+ locationAwareLogger.log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, null, t);
+ }
+ } else if (Level.CONFIG.equals(level)) {
+ if (locationAwareLogger == null) {
+ logger.debug(msg, t);
+ } else {
+ locationAwareLogger.log(null, FQCN, LocationAwareLogger.DEBUG_INT, msg, null, t);
+ }
+ }
+ // don't log if Level.OFF
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/d9964c64/dormant/core/src/main/java/org/apache/tamaya/core/internal/resources/AntPathClasspathResolver.java
----------------------------------------------------------------------
diff --git a/dormant/core/src/main/java/org/apache/tamaya/core/internal/resources/AntPathClasspathResolver.java b/dormant/core/src/main/java/org/apache/tamaya/core/internal/resources/AntPathClasspathResolver.java
new file mode 100644
index 0000000..38a9644
--- /dev/null
+++ b/dormant/core/src/main/java/org/apache/tamaya/core/internal/resources/AntPathClasspathResolver.java
@@ -0,0 +1,60 @@
+/*
+ * 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.core.internal.resources;
+
+import org.apache.tamaya.core.internal.resources.io.PathMatchingResourcePatternResolver;
+import org.apache.tamaya.core.spi.PathResolver;
+import org.apache.tamaya.core.resource.Resource;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class AntPathClasspathResolver implements PathResolver {
+
+ private static final Logger LOG = Logger.getLogger(AntPathClasspathResolver.class.getName());
+
+ @Override
+ public String getResolverId(){
+ return "classpath";
+ }
+
+ @Override
+ public Collection<Resource> resolve(ClassLoader classLoader, Collection<String> expressions){
+ PathMatchingResourcePatternResolver resolver = PathMatchingResourcePatternResolver.of(classLoader);
+ List<Resource> result = new ArrayList<>();
+ expressions.forEach((expression) -> {
+ try {
+ Resource[] resources = resolver.getResources(expression);
+ for (Resource res : resources) {
+ try {
+ result.add(res);
+ } catch (Exception e) {
+ LOG.log(Level.FINEST, "URI could not be extracted from Resource: " + res.toString(), e);
+ }
+ }
+ }
+ catch(IOException e){
+ LOG.log(Level.FINE, "Failed to load resource expression: " + expression, e);
+ }
+ });
+ return result;
+ }
+}