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 2016/10/30 17:25:46 UTC
[04/10] incubator-tamaya-sandbox git commit: TAMAYA-182: Adapted
modules to new builder patter changes, including tests. Fixed compile errors,
or excluded modules from compilation (see root pom).
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/usagetracker/src/test/resources/examples/configmodel.xml
----------------------------------------------------------------------
diff --git a/usagetracker/src/test/resources/examples/configmodel.xml b/usagetracker/src/test/resources/examples/configmodel.xml
new file mode 100644
index 0000000..f23f783
--- /dev/null
+++ b/usagetracker/src/test/resources/examples/configmodel.xml
@@ -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.
+-->
+
+<!--################################################################################
+# Example of a configuration metamodel expressed via YAML(tm).
+# Structure is shown through indentation (one or more spaces).
+# Sequence items are denoted by a dash,
+# key value pairs within a map are separated by a colon.
+#################################################################################-->
+
+<!--################################################################################
+# Metamodel information
+#################################################################################-->
+
+<configuration>
+ <section name="{model}" __provider="ConfigModel Extension" version="1.0" __release-date="2001-01-23"
+ author="Anatole Tresch">
+ <!-- model-format>alternate format reader type</model-format -->
+ <__description>Late afternoon is best.
+ Backup contact is Nancy.
+ </__description>
+
+ <!--################################################################################
+ # Description of Configuration Sections (minimal, can be extended by other modules).
+ #################################################################################-->
+ <section name="a">
+ <param name="params">
+ <type>String</type>
+ <required>true</required>
+ <description>a required parameter</description>
+ </param>
+ <param name="paramInt">
+ <ref>MyNumber</ref>
+ <required>true</required>
+ <description>an optional parameter (default)</description>
+ </param>
+ <param name="_number">
+ <type>Integer</type>
+ <deprecated>true</deprecated>
+ <mappedto>a.paramInt</mappedto>
+ </param>
+ <section name="b.c">
+ <description>Just a test section.</description>
+ <section name="aRequiredSection">
+ <description>A section containing required parameters is called a required section.
+ Sections can also explicitly be defined to be required, but without
+ specifying the paramteres to be contained.
+ </description>
+ </section>
+ </section>
+ </section>
+
+ <section name="a.b.c.aRequiredSection.subsection">
+ <param name="param0" type="String">a minmally documented String parameter</param>
+ <!-- # A minmally defined String parameter -->
+ <param name="param00">
+ <type>String</type>
+ </param>
+ <param name="param1">
+ <type>String</type>
+ <required>true</required>
+ <description>a required parameter</description>description>
+ </param>
+ <param name="intParam">
+ <type>Integer</type>
+ <description>an optional parameter (default)</description>
+ </param>
+ <section name="b.c">
+ <description>Just a test section.</description>
+ </section>
+ </section>
+ <section name="a.b.c.aRequiredSection.nonempty-subsection">
+ <required>true</required>
+ </section>
+ <section name="a.b.c.aRequiredSection.optional-subsection"/>
+ <section name="a.b.c.aRequiredSection.aValidatedSection">
+ <configModels>org.apache.tamaya.model.configModel.MaxItemValidator?max=3"</configModels>
+ <description>A configModel section.</description>
+ </section>
+ </section>
+</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/usagetracker/src/test/resources/examples/configmodel.yaml
----------------------------------------------------------------------
diff --git a/usagetracker/src/test/resources/examples/configmodel.yaml b/usagetracker/src/test/resources/examples/configmodel.yaml
new file mode 100644
index 0000000..041c801
--- /dev/null
+++ b/usagetracker/src/test/resources/examples/configmodel.yaml
@@ -0,0 +1,106 @@
+#
+# 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.
+#
+
+##################################################################################
+# Example of a configuration metamodel expressed via YAML(tm).
+# Structure is shown through indentation (one or more spaces).
+# Sequence items are denoted by a dash,
+# key value pairs within a map are separated by a colon.
+####################################################################################
+
+####################################################################################
+# Metamodel information
+####################################################################################
+{model}: {
+ __name : 'testmodel',
+ __provider : 'ValidationProviderSpi Extension',
+ __version : '1.0',
+ __release-date : 2001-01-23,
+ __author : 'Anatole Tresch',
+ # model-format: 'alternate format reader type'
+ __description: >
+ Late afternoon is best.
+ Backup contact is Nancy.
+}
+
+####################################################################################
+# Description of Configuration Sections (minimal, can be extended by other modules).
+####################################################################################
+---
+{model}.a.params2: {
+ type : 'String',
+ required : true,
+ description : 'a required parameter',
+ paramInt: 'Integer', 'an optional parameter (default)',
+}
+---
+{model}.a.paramInt: {
+ type : 'Integer',
+ description : 'an optional parameter (default)',
+}
+---
+{model}.a.b.c: {
+ description: 'Just a test section.'
+}
+---
+{model}.a.b.c.aRequiredSection: {
+ required: true,
+ description: |
+ A section containing required parameters is called a required section.
+ Sections can also explicitly be defined to be required, but without
+ specifying the paramteres to be contained.,
+}
+---
+{model}.a.b.c.aRequiredSection.subsection: {
+ param0: {
+ type: 'String',
+ description: 'a minmally documented String parameter}'
+ }, ,
+ param00:{
+ type: 'String' # A minmally defined String parameter
+ },
+ param1: {
+ tpye: 'String',
+ required: true,
+ description: 'a required parameter'
+ },
+ intParam: {
+ type: 'Integer',
+ description: 'an optional parameter (default)'
+ }
+}
+...
+
+---
+{model}.a.b.c.aRequiredSection.nonempty-subsection: {
+ required: true
+}
+...
+
+---
+{model}.a.b.c.aRequiredSection.optional-subsection: {}
+...
+
+---
+{model}.a.b.c.aRequiredSection.aValidatedSection: {
+ description: 'A configModel section.',
+ configModels: 'org.apache.tamaya.model.configModel.MaxItemValidator?max=3'
+}
+
+
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/ConfigModel.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/ConfigModel.java b/validation/src/main/java/org/apache/tamaya/validation/ConfigModel.java
new file mode 100644
index 0000000..a9c58f0
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/ConfigModel.java
@@ -0,0 +1,78 @@
+/*
+ * 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.validation;
+
+import org.apache.tamaya.Configuration;
+
+import java.util.Collection;
+
+/**
+ * Base structure describing a validated item, by default a parameter or a section.
+ */
+public interface ConfigModel {
+
+ /**
+ * Access the owner.
+ * @return the owner of this model, never null.
+ */
+ String getOwner();
+
+ /**
+ * Get the type of item that is modelled.
+ * @return the modelled type, never null.
+ */
+ ModelTarget getType();
+
+ /**
+ * Get the item's name, it should minimally describe the validation. Examples are:
+ * <pre>
+ * Sections: a.b.c
+ * Params: a.b.c.paramName
+ * Filter: a.b.c.FilterImplClass
+ * Dependency: mydepClassname
+ * CombinationPolicy: a.b.c.MyCombinationPolicyClass
+ * </pre>
+ * @return the item's name.
+ */
+ String getName();
+
+ /**
+ * Check if this validation is a required one.
+ * @return true, if this validation is required.
+ */
+ boolean isRequired();
+
+ /**
+ * Get an description of the item, using the default locale. The description is basically optional
+ * though it is higly recommended to provide a description, so the validation issues is well
+ * resolvable.
+ *
+ * @return the description required, or null.
+ */
+ String getDescription();
+
+ /**
+ * Validates the item and all its children against the given configuration.
+ *
+ * @param config the configuration to be validated against, not null.
+ * @return the validation result, or null, if not applicable.
+ */
+ Collection<Validation> validate(Configuration config);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/ConfigModelManager.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/ConfigModelManager.java b/validation/src/main/java/org/apache/tamaya/validation/ConfigModelManager.java
new file mode 100644
index 0000000..0f3cce5
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/ConfigModelManager.java
@@ -0,0 +1,298 @@
+/*
+ * 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.validation;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.validation.spi.ConfigDocumentationMBean;
+import org.apache.tamaya.validation.spi.ModelProviderSpi;
+import org.apache.tamaya.spi.ServiceContextManager;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Validator accessor to validate the current configuration.
+ */
+public final class ConfigModelManager {
+
+ /** The logger used. */
+ private static final Logger LOG = Logger.getLogger(ConfigModelManager.class.getName());
+
+ /**
+ * Singleton constructor.
+ */
+ private ConfigModelManager() {
+ }
+
+ /**
+ * Access the usage statistics for the recorded uses of configuration.
+ * @return usage statistics
+ */
+ public static String getConfigInfoText(){
+ StringBuilder b = new StringBuilder();
+ List<ConfigModel> models = new ArrayList<>(getModels());
+ Collections.sort(models, new Comparator<ConfigModel>() {
+ @Override
+ public int compare(ConfigModel k1, ConfigModel k2) {
+ return k2.getName().compareTo(k2.getName());
+ }
+ });
+ b.append("TYPE OWNER NAME MANDATORY DESCRIPTION\n");
+ b.append("-----------------------------------------------------------------------------------------------------\n");
+ for(ConfigModel model:models){
+ switch(model.getType()){
+ case Parameter:
+ b.append("PARAM ");
+ break;
+ case Section:
+ b.append("SECTION ");
+ break;
+ case Group:
+ b.append("GROUP ");
+ break;
+ default:
+ break;
+ }
+ b.append(formatWithFixedLength(model.getOwner(), 10)).append(' ');
+ b.append(formatWithFixedLength(model.getName(), 50));
+ if(model.isRequired()){
+ b.append(formatWithFixedLength("yes", 12));
+ }else{
+ b.append(formatWithFixedLength("no", 12));
+ }
+ if(model.getDescription()!=null){
+ b.append(model.getDescription().replace("\n", "\\\n").replace("\"", "'")).append("\"");
+ }
+ b.append("\n");
+ }
+ return b.toString();
+ }
+
+ private static String formatWithFixedLength(String name, int targetLength) {
+ targetLength = targetLength-1;
+ StringBuilder b = new StringBuilder();
+ if(name.length() > targetLength){
+ name = name.substring(0, targetLength);
+ }
+ b.append(name);
+ for(int i=0;i<(targetLength-name.length());i++){
+ b.append(' ');
+ }
+ b.append(' ');
+ return b.toString();
+ }
+
+ /**
+ * Get the validations defined.
+ *
+ * @return the sections defined, never null.
+ */
+ public static Collection<ConfigModel> getModels() {
+ List<ConfigModel> result = new ArrayList<>();
+ for (ModelProviderSpi model : ServiceContextManager.getServiceContext().getServices(ModelProviderSpi.class)) {
+ result.addAll(model.getConfigModels());
+ }
+ return result;
+ }
+
+
+ /**
+ * Find the validations by matching the validation's name against the given model type.
+ *
+ * @param name the name to use, not null.
+ * @param modelType classname of the target model type.
+ * @param <T> type of the model to filter for.
+ * @return the sections defined, never null.
+ */
+ public static <T extends ConfigModel> T getModel(String name, Class<T> modelType) {
+ for (ModelProviderSpi model : ServiceContextManager.getServiceContext().getServices(ModelProviderSpi.class)) {
+ for(ConfigModel configModel : model.getConfigModels()) {
+ if(configModel.getName().equals(name) && configModel.getClass().equals(modelType)) {
+ return modelType.cast(configModel);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Find the validations by checking the validation's name using the given regular expression.
+ * @param namePattern the regular expression to use, not null.
+ * @param targets the target types only to be returned (optional).
+ * @return the sections defined, never null.
+ */
+ public static Collection<ConfigModel> findModels(String namePattern, ModelTarget... targets) {
+ List<ConfigModel> result = new ArrayList<>();
+ for (ModelProviderSpi model : ServiceContextManager.getServiceContext().getServices(ModelProviderSpi.class)) {
+ for(ConfigModel configModel : model.getConfigModels()) {
+ if(configModel.getName().matches(namePattern)) {
+ if(targets.length>0){
+ for(ModelTarget tgt:targets){
+ if(configModel.getType().equals(tgt)){
+ result.add(configModel);
+ break;
+ }
+ }
+ }else {
+ result.add(configModel);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Validates the current configuration.
+ *
+ * @return the validation results, never null.
+ */
+ public static Collection<Validation> validate() {
+ return validate(false);
+ }
+
+ /**
+ * Validates the current configuration.
+ * @param showUndefined show any unknown parameters.
+ * @return the validation results, never null.
+ */
+ public static Collection<Validation> validate(boolean showUndefined) {
+ return validate(ConfigurationProvider.getConfiguration(), showUndefined);
+ }
+
+ /**
+ * Validates the given configuration.
+ *
+ * @param config the configuration to be validated against, not null.
+ * @return the validation results, never null.
+ */
+ public static Collection<Validation> validate(Configuration config) {
+ return validate(config, false);
+ }
+
+ /**
+ * Validates the given configuration.
+ *
+ * @param config the configuration to be validated against, not null.
+ * @param showUndefined allows filtering for undefined configuration elements.
+ * @return the validation results, never null.
+ */
+ public static Collection<Validation> validate(Configuration config, boolean showUndefined) {
+ List<Validation> result = new ArrayList<>();
+ for (ConfigModel defConf : getModels()) {
+ result.addAll(defConf.validate(config));
+ }
+ if(showUndefined){
+ Map<String,String> map = new HashMap<>(config.getProperties());
+ Set<String> areas = extractTransitiveAreas(map.keySet());
+ for (ConfigModel defConf : getModels()) {
+ if(ModelTarget.Section.equals(defConf.getType())){
+ for (Iterator<String> iter = areas.iterator();iter.hasNext();){
+ String area = iter.next();
+ if(area.matches(defConf.getName())){
+ iter.remove();
+ }
+ }
+ }
+ if(ModelTarget.Parameter.equals(defConf.getType())){
+ map.remove(defConf.getName());
+ }
+ }
+ outer:for(Map.Entry<String,String> entry:map.entrySet()){
+ for (ConfigModel defConf : getModels()) {
+ if(ModelTarget.Section.equals(defConf.getType())){
+ if(defConf.getName().endsWith(".*") && entry.getKey().matches(defConf.getName())){
+ // Ignore parameters that are part of transitive section.
+ continue outer;
+ }
+ }
+ }
+ result.add(Validation.ofUndefined("<auto>", entry.getKey(), ModelTarget.Parameter));
+ }
+ for(String area:areas){
+ result.add(Validation.ofUndefined("<auto>", area, ModelTarget.Section));
+ }
+ }
+ return result;
+ }
+
+ private static java.util.Set<java.lang.String> extractTransitiveAreas(Set<String> keys) {
+ Set<String> transitiveClosure = new HashSet<>();
+ for(String key:keys){
+ int index = key.lastIndexOf('.');
+ while(index>0){
+ String areaKey = key.substring(0,index);
+ transitiveClosure.add(areaKey);
+ index = areaKey.lastIndexOf('.');
+ }
+ }
+ return transitiveClosure;
+ }
+
+
+ /**
+ * Registers the {@link ConfigDocumentationMBean} mbean for accessing config documentation into the local platform
+ * mbean server.
+ */
+ public static void registerMBean() {
+ registerMBean(null);
+ }
+
+ /**
+ * Registers the {@link ConfigDocumentationMBean} mbean for accessing config documentation into the local platform
+ * mbean server.
+ *
+ * @param context allows to specify an additional MBean context, maybe {@code null}.
+ */
+ public static void registerMBean(String context) {
+ try{
+ ConfigDocumentationMBean configMbean = ServiceContextManager.getServiceContext()
+ .getService(ConfigDocumentationMBean.class);
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ ObjectName on = context==null?new ObjectName("org.apache.tamaya.model:type=ConfigDocumentationMBean"):
+ new ObjectName("org.apache.tamaya.model:type=ConfigDocumentationMBean,context="+context);
+ try{
+ mbs.getMBeanInfo(on);
+ LOG.warning("Cannot register mbean " + on + ": already existing.");
+ } catch(InstanceNotFoundException e) {
+ LOG.info("Registering mbean " + on + "...");
+ mbs.registerMBean(configMbean, on);
+ }
+ } catch(Exception e){
+ LOG.log(Level.WARNING,
+ "Failed to register ConfigDocumentationMBean.", e);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/ModelTarget.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/ModelTarget.java b/validation/src/main/java/org/apache/tamaya/validation/ModelTarget.java
new file mode 100644
index 0000000..e087c66
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/ModelTarget.java
@@ -0,0 +1,37 @@
+/*
+ * 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.validation;
+
+/**
+ * This enumeration defines the types of supported validations.
+ */
+public enum ModelTarget {
+ /**
+ * A configuration section.
+ */
+ Section,
+ /**
+ * A configuration paramter.
+ */
+ Parameter,
+ /**
+ * ConfigModel that is a container of other validations.
+ */
+ Group,
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/Validation.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/Validation.java b/validation/src/main/java/org/apache/tamaya/validation/Validation.java
new file mode 100644
index 0000000..81a0118
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/Validation.java
@@ -0,0 +1,203 @@
+/*
+ * 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.validation;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.validation.spi.AbstractConfigModel;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
+/**
+ * Models a partial configuration configModel result.
+ */
+public final class Validation {
+ /**
+ * the config section.
+ */
+ private final ConfigModel configModel;
+ /**
+ * The configModel result.
+ */
+ private final ValidationResult result;
+ /**
+ * The configModel message.
+ */
+ private final String message;
+
+ /**
+ * Creates a new ValidationResult.
+ *
+ * @param configModel the configModel item, not null.
+ * @return a new validation result containing valid parts of the given model.
+ */
+ public static Validation ofValid(ConfigModel configModel) {
+ return new Validation(configModel, ValidationResult.VALID, null);
+ }
+
+ /**
+ * Creates a new ValidationResult.
+ *
+ * @param configModel the configModel item, not null.
+ * @return a new validation result containing missing parts of the given model.
+ */
+ public static Validation ofMissing(ConfigModel configModel) {
+ return new Validation(configModel, ValidationResult.MISSING, null);
+ }
+
+ /**
+ * Creates a new ValidationResult.
+ *
+ * @param configModel the configModel item, not null.
+ * @param message Additional message to be shown (optional).
+ * @return a new validation result containing missing parts of the given model with a message.
+ */
+ public static Validation ofMissing(ConfigModel configModel, String message) {
+ return new Validation(configModel, ValidationResult.MISSING, message);
+ }
+
+ /**
+ * Creates a new ValidationResult.
+ *
+ * @param configModel the configModel item, not null.
+ * @param error error message to add.
+ * @return a new validation result containing erroneous parts of the given model with the given error message.
+ */
+ public static Validation ofError(ConfigModel configModel, String error) {
+ return new Validation(configModel, ValidationResult.ERROR, error);
+ }
+
+ /**
+ * Creates a new ValidationResult.
+ *
+ * @param configModel the configModel item, not null.
+ * @param warning warning message to add.
+ * @return a new validation result containing warning parts of the given model with the given warning message.
+ */
+ public static Validation ofWarning(ConfigModel configModel, String warning) {
+ return new Validation(configModel, ValidationResult.WARNING, warning);
+ }
+
+ /**
+ * Creates a new ValidationResult.
+ *
+ * @param configModel the configModel item, not null.
+ * @param alternativeUsage allows setting a message to indicate non-deprecated replacement, maybe null.
+ * @return a new validation result containing deprecated parts of the given model with an optional message.
+ */
+ public static Validation ofDeprecated(ConfigModel configModel, String alternativeUsage) {
+ return new Validation(configModel, ValidationResult.DEPRECATED, alternativeUsage != null ? "Use instead: " + alternativeUsage : null);
+ }
+
+ /**
+ * Creates a new ValidationResult.
+ *
+ * @param configModel the configModel item, not null.
+ * @return a new validation result containing deprecated parts of the given model.
+ */
+ public static Validation ofDeprecated(ConfigModel configModel) {
+ return new Validation(configModel, ValidationResult.DEPRECATED, null);
+ }
+
+ /**
+ * Creates a new ValidationResult.
+ *
+ * @param owner owner
+ * @param key the name/model key
+ * @param type model type
+ * @return a corresponding configModel item
+ */
+ public static Validation ofUndefined(final String owner, final String key, final ModelTarget type) {
+ return new Validation(new AbstractConfigModel(owner, key, false, "Undefined key: " + key) {
+
+ @Override
+ public ModelTarget getType() {
+ return type;
+ }
+
+ @Override
+ public Collection<Validation> validate(Configuration config) {
+ return Collections.emptyList();
+ }
+ }, ValidationResult.UNDEFINED, null);
+ }
+
+
+ /**
+ * Constructor.
+ *
+ * @param configModel the configModel item, not null.
+ * @param result the configModel result, not null.
+ * @param message the detail message.
+ * @return new validation result.
+ */
+ public static Validation of(ConfigModel configModel, ValidationResult result, String message) {
+ return new Validation(configModel, result, message);
+ }
+
+
+ /**
+ * Constructor.
+ *
+ * @param configModel the configModel item, not null.
+ * @param result the configModel result, not null.
+ * @param message the detail message.
+ */
+ private Validation(ConfigModel configModel, ValidationResult result, String message) {
+ this.message = message;
+ this.configModel = Objects.requireNonNull(configModel);
+ this.result = Objects.requireNonNull(result);
+ }
+
+ /**
+ * Get the configModel section.
+ *
+ * @return the section, never null.
+ */
+ public ConfigModel getConfigModel() {
+ return configModel;
+ }
+
+ /**
+ * Get the configModel result.
+ *
+ * @return the result, never null.
+ */
+ public ValidationResult getResult() {
+ return result;
+ }
+
+ /**
+ * Get the detail message.
+ *
+ * @return the detail message, or null.
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String toString() {
+ if (message != null) {
+ return result + ": " + configModel.getName() + " (" + configModel.getType() + ") -> " + message + '\n';
+ }
+ return result + ": " + configModel.getName() + " (" + configModel.getType() + ")";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/ValidationResult.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/ValidationResult.java b/validation/src/main/java/org/apache/tamaya/validation/ValidationResult.java
new file mode 100644
index 0000000..f368985
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/ValidationResult.java
@@ -0,0 +1,59 @@
+/*
+ * 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.validation;
+
+/**
+ * Enum type describing the different validation results supported.
+ */
+public enum ValidationResult {
+ /**
+ * The validated item is valid
+ */
+ VALID,
+ /**
+ * The validated item is deprecated.
+ */
+ DEPRECATED,
+ /**
+ * The validated item is correct, but the value is worth a warning.
+ */
+ WARNING,
+ /**
+ * The given section or parameter is not a defined/validated item. It may be still valid, but typically,
+ * when validation is fully implemented, such a parameter or section should be removed.
+ */
+ UNDEFINED,
+ /**
+ * A required parameter or section is missing.
+ */
+ MISSING,
+ /**
+ * The validated item has an invalid value.
+ */
+ ERROR;
+
+ /**
+ * Method to quickly evaluate if the current state is an error state.
+ *
+ * @return true, if the state is not ERROR or MISSING.
+ */
+ boolean isError() {
+ return this.ordinal() == MISSING.ordinal() || this.ordinal() == ERROR.ordinal();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/internal/ConfigDocumentationBean.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/internal/ConfigDocumentationBean.java b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfigDocumentationBean.java
new file mode 100644
index 0000000..59c5c22
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfigDocumentationBean.java
@@ -0,0 +1,197 @@
+/*
+ * 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.validation.internal;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.validation.ConfigModel;
+import org.apache.tamaya.validation.ConfigModelManager;
+import org.apache.tamaya.validation.ModelTarget;
+import org.apache.tamaya.validation.Validation;
+import org.apache.tamaya.validation.spi.ConfigDocumentationMBean;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonWriter;
+import javax.json.JsonWriterFactory;
+import javax.json.stream.JsonGenerator;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * MBean implementation of {@link ConfigDocumentationMBean}.
+ */
+public class ConfigDocumentationBean implements ConfigDocumentationMBean{
+
+ private final JsonWriterFactory writerFactory;
+
+ private static final Comparator<Validation> COMPARATOR = new Comparator<Validation>() {
+ @Override
+ public int compare(Validation v1, Validation v2) {
+ int compare = VAL_COMPARATOR.compare(v1.getConfigModel(), v2.getConfigModel());
+ if(compare==0){
+ compare = v1.getResult().compareTo(v2.getResult());
+ }
+ if(compare==0){
+ return v1.getMessage().compareTo(v2.getMessage());
+ }
+ return compare;
+ }
+ };
+ private static final Comparator<ConfigModel> VAL_COMPARATOR = new Comparator<ConfigModel>() {
+ @Override
+ public int compare(ConfigModel v1, ConfigModel v2) {
+ int compare = v1.getType().compareTo(v2.getType());
+ if(compare==0){
+ compare = v1.getName().compareTo(v2.getName());
+ }
+ return compare;
+ }
+ };
+
+ private Configuration config;
+
+ /**
+ * Default constructor, using the current configuration being available.
+ */
+ public ConfigDocumentationBean(){
+ this(null);
+ }
+
+
+ /**
+ * Creates an mbean bound to the given configuration. This is useful, when multiple mbeans for each
+ * context should be used, e.g. one mbean per ear, app deployment.
+ * @param config the configuration to be used.
+ */
+ public ConfigDocumentationBean(Configuration config){
+ this.config = config;
+ Map<String, Object> writerProperties = new HashMap<>(1);
+ writerProperties.put(JsonGenerator.PRETTY_PRINTING, true);
+ writerFactory = Json.createWriterFactory(writerProperties);
+ }
+
+ /**
+ * Access the configuration.
+ * @return either the configuration bound to this bean, or the current configuration.
+ */
+ private Configuration getConfig(){
+ return config!=null?config: ConfigurationProvider.getConfiguration();
+ }
+
+ @Override
+ public String validate(boolean showUndefined) {
+ List<Validation> validations = new ArrayList<>(ConfigModelManager.validate(getConfig(), showUndefined));
+ Collections.sort(validations, COMPARATOR);
+ JsonArrayBuilder builder = Json.createArrayBuilder();
+ for(Validation val:validations){
+ builder.add(toJsonObject(val));
+ }
+ return formatJson(builder.build());
+ }
+
+
+
+ @Override
+ public String getConfigurationModel() {
+ List<ConfigModel> configModels = new ArrayList<>(ConfigModelManager.getModels());
+ Collections.sort(configModels, VAL_COMPARATOR);
+ JsonArrayBuilder result = Json.createArrayBuilder();
+ for(ConfigModel val: configModels){
+ result.add(toJsonObject(val));
+ }
+ return formatJson(result.build());
+ }
+
+ @Override
+ public String getConfigurationModel(ModelTarget type) {
+ return findValidationModels(".*", type);
+ }
+
+ @Override
+ public String findConfigurationModels(String namePattern) {
+ List<ConfigModel> configModels = new ArrayList<>(ConfigModelManager.findModels(namePattern));
+ Collections.sort(configModels, VAL_COMPARATOR);
+ JsonArrayBuilder result = Json.createArrayBuilder();
+ for(ConfigModel val: configModels){
+ result.add(toJsonObject(val));
+ }
+ return formatJson(result.build());
+ }
+
+ @Override
+ public String findValidationModels(String namePattern, ModelTarget... type) {
+ List<ConfigModel> configModels = new ArrayList<>(ConfigModelManager.findModels(namePattern, type));
+ Collections.sort(configModels, VAL_COMPARATOR);
+ JsonArrayBuilder result = Json.createArrayBuilder();
+ for(ConfigModel val: configModels){
+ result.add(toJsonObject(val));
+ }
+ return formatJson(result.build());
+ }
+
+ @Override
+ public String toString(){
+ return "ConfigDocumentationBean, config: " + (this.config!=null?this.config.toString():"<current>");
+ }
+
+
+ private JsonObject toJsonObject(ConfigModel val) {
+ JsonObjectBuilder valJson = Json.createObjectBuilder().add("target", val.getType().toString())
+ .add("name", val.getName());
+ if(val.getDescription()!=null) {
+ valJson.add("description", val.getDescription());
+ }
+ if(val.isRequired()){
+ valJson.add("required",true);
+ }
+ return valJson.build();
+ }
+
+ private JsonObject toJsonObject(Validation val) {
+ JsonObjectBuilder valJson = Json.createObjectBuilder().add("target", val.getConfigModel().getType().toString())
+ .add("name", val.getConfigModel().getName());
+ if(val.getConfigModel().isRequired()){
+ valJson.add("required",true);
+ }
+ if(val.getConfigModel().getDescription() != null){
+ valJson.add("description", val.getConfigModel().getDescription());
+ }
+ valJson.add("result", val.getResult().toString());
+ if( val.getMessage() != null) {
+ valJson.add("message", val.getMessage());
+ }
+ return valJson.build();
+ }
+
+ private String formatJson(JsonArray data) {
+ StringWriter writer = new StringWriter();
+ JsonWriter gen = writerFactory.createWriter(writer);
+ gen.writeArray(data);
+ return writer.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredInlineModelProviderSpi.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredInlineModelProviderSpi.java b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredInlineModelProviderSpi.java
new file mode 100644
index 0000000..6658bb5
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredInlineModelProviderSpi.java
@@ -0,0 +1,69 @@
+/*
+ * 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.validation.internal;
+
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.validation.ConfigModel;
+import org.apache.tamaya.validation.spi.ConfigModelReader;
+import org.apache.tamaya.validation.spi.ModelProviderSpi;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * ConfigModel provider that reads model metadata from the current {@link org.apache.tamaya.Configuration}.
+ */
+public class ConfiguredInlineModelProviderSpi implements ModelProviderSpi {
+
+ /** The logger. */
+ private static final Logger LOG = Logger.getLogger(ConfiguredInlineModelProviderSpi.class.getName());
+ /** parameter to disable this provider. By default the provider is active. */
+ private static final String MODEL_EANABLED_PARAM = "org.apache.tamaya.model.integrated.enabled";
+
+ /** The configModels read. */
+ private List<ConfigModel> configModels = new ArrayList<>();
+
+
+ /**
+ * Constructor, typically called by the {@link java.util.ServiceLoader}.
+ */
+ public ConfiguredInlineModelProviderSpi() {
+ String enabledVal = ConfigurationProvider.getConfiguration().get(MODEL_EANABLED_PARAM);
+ boolean enabled = enabledVal == null || "true".equalsIgnoreCase(enabledVal);
+ if (enabled) {
+ LOG.info("Reading model configuration from config...");
+ Map<String,String> config = ConfigurationProvider.getConfiguration().getProperties();
+ String owner = config.get("_model.provider");
+ if(owner==null){
+ owner = config.toString();
+ }
+ configModels.addAll(ConfigModelReader.loadValidations(owner, config));
+ }
+ configModels = Collections.unmodifiableList(configModels);
+ }
+
+
+ public Collection<ConfigModel> getConfigModels() {
+ return configModels;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredPropertiesModelProviderSpi.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredPropertiesModelProviderSpi.java b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredPropertiesModelProviderSpi.java
new file mode 100644
index 0000000..97e23c6
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredPropertiesModelProviderSpi.java
@@ -0,0 +1,154 @@
+/*
+ * 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.validation.internal;
+
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.validation.ConfigModel;
+import org.apache.tamaya.validation.spi.ConfigModelReader;
+import org.apache.tamaya.validation.spi.ModelProviderSpi;
+import org.apache.tamaya.spisupport.MapPropertySource;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * ConfigModel provider that reads model metadata from property files from
+ * {@code classpath*:META-INF/configmodel.properties} in the following format:
+ * <pre>
+ * ###################################################################################
+ * # Example of a configuration metamodel expressed via properties.
+ * ####################################################################################
+ *
+ * # Metamodel information
+ * [model].provider=ConfigModel Extension
+ *
+ * ####################################################################################
+ * # Description of Configuration Sections (minimal, can be extended by other modules).
+ * # By default its interpreted as a section !
+ * ####################################################################################
+ *
+ * # a (section)
+ * {model}a.class=Section
+ * {model}a.params2.class=Parameter
+ * {model}a.params2.type=String
+ * {model}a.params2.required=true
+ * {model}a.params2.description=a required parameter
+ *
+ * {model}a.paramInt.class=Parameter
+ * {model}a.paramInt.ref=MyNumber
+ * {model}a.paramInt.description=an optional parameter (default)
+ *
+ * {model}a._number.class=Parameter
+ * {model}a._number.type=Integer
+ * {model}a._number.deprecated=true
+ * {model}a._number.mappedTo=a.paramInt
+ *
+ * # a.b.c (section)
+ * {model}a.b.c.class=Section
+ * {model}a.b.c.description=Just a test section
+ *
+ * # a.b.c.aRequiredSection (section)
+ * {model}a.b.c.aRequiredSection.class=Section
+ * {model}a.b.c.aRequiredSection.required=true
+ * {model}a.b.c.aRequiredSection.description=A section containing required parameters is called a required section.\
+ * Sections can also explicitly be defined to be required, but without\
+ * specifying the paramteres to be contained.,
+ *
+ * # a.b.c.aRequiredSection.subsection (section)
+ * {model}a.b.c.aRequiredSection.subsection.class=Section
+ *
+ * {model}a.b.c.aRequiredSection.subsection.param0.class=Parameter
+ * {model}a.b.c.aRequiredSection.subsection.param0.type=String
+ * {model}a.b.c.aRequiredSection.subsection.param0.description=a minmally documented String parameter
+ * # A minmal String parameter
+ * {model}a.b.c.aRequiredSection.subsection.param00.class=Parameter
+ * {model}a.b.c.aRequiredSection.subsection.param00.type=String
+ *
+ * # a.b.c.aRequiredSection.subsection (section)
+ * {model}a.b.c.aRequiredSection.subsection.param1.class=Parameter
+ * {model}a.b.c.aRequiredSection.subsection.param1.type = String
+ * {model}a.b.c.aRequiredSection.subsection.param1.required = true
+ * {model}a.b.c.aRequiredSection.subsection.intParam.class=Parameter
+ * {model}a.b.c.aRequiredSection.subsection.intParam.type = Integer
+ * {model}a.b.c.aRequiredSection.subsection.intParam.description=an optional parameter (default)
+ *
+ * # a.b.c.aRequiredSection.nonempty-subsection (section)
+ * {model}a.b.c.aRequiredSection.nonempty-subsection.class=Section
+ * {model}a.b.c.aRequiredSection.nonempty-subsection.required=true
+ *
+ * # a.b.c.aRequiredSection.optional-subsection (section)
+ * {model}a.b.c.aRequiredSection.optional-subsection.class=Section
+ *
+ * # a.b.c.aValidatedSection (section)
+ * {model}a.b.c.aValidatedSection.class=Section
+ * {model}a.b.c.aValidatedSection.description=A validated section.
+ * {model}a.b.c.aValidatedSection.configModels=org.apache.tamaya.model.TestValidator
+ * </pre>
+ */
+public class ConfiguredPropertiesModelProviderSpi implements ModelProviderSpi {
+
+ /** The logger. */
+ private static final Logger LOG = Logger.getLogger(ConfiguredPropertiesModelProviderSpi.class.getName());
+ /** parameter to disable this provider. By default the provider is active. */
+ private static final String MODEL_EANABLED_PARAM = "org.apache.tamaya.model.default.enabled";
+ /** The configModels read. */
+ private List<ConfigModel> configModels = new ArrayList<>();
+
+ public ConfiguredPropertiesModelProviderSpi() {
+ String enabledVal = ConfigurationProvider.getConfiguration().get(MODEL_EANABLED_PARAM);
+ boolean enabled = enabledVal == null || "true".equalsIgnoreCase(enabledVal);
+ if(!enabled){
+ LOG.info("Reading model data from META-INF/configmodel.properties has been disabled.");
+ return;
+ }
+ try {
+ LOG.info("Reading model data from META-INF/configmodel.properties...");
+ Enumeration<URL> configs = getClass().getClassLoader().getResources("META-INF/configmodel.properties");
+ while (configs.hasMoreElements()) {
+ URL config = configs.nextElement();
+ try (InputStream is = config.openStream()) {
+ Properties props = new Properties();
+ props.load(is);
+ Map<String,String> data = MapPropertySource.getMap(props);
+ String owner = data.get("_model.owner");
+ if(owner==null){
+ owner = config.toString();
+ }
+ configModels.addAll(ConfigModelReader.loadValidations(owner,
+ data));
+ } catch (Exception e) {
+ Logger.getLogger(getClass().getName()).log(Level.SEVERE,
+ "Error loading config metadata from " + config, e);
+ }
+ }
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE,
+ "Error loading config metadata from META-INF/configmodel.properties", e);
+ }
+ configModels = Collections.unmodifiableList(configModels);
+ }
+
+
+ public Collection<ConfigModel> getConfigModels() {
+ return configModels;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredResourcesModelProviderSpi.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredResourcesModelProviderSpi.java b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredResourcesModelProviderSpi.java
new file mode 100644
index 0000000..1894570
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredResourcesModelProviderSpi.java
@@ -0,0 +1,160 @@
+/*
+ * 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.validation.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tamaya.ConfigurationProvider;
+import org.apache.tamaya.format.ConfigurationData;
+import org.apache.tamaya.format.ConfigurationFormats;
+import org.apache.tamaya.validation.ConfigModel;
+import org.apache.tamaya.validation.spi.ConfigModelReader;
+import org.apache.tamaya.validation.spi.ModelProviderSpi;
+import org.apache.tamaya.resource.ConfigResources;
+
+/**
+ * ConfigModel provider that reads model metadata from property files from
+ * {@code classpath*:META-INF/configmodel.json} in the following format:
+ * <pre>
+ * Example of a configuration metamodel expressed via YAML.
+ * Structure is shown through indentation (one or more spaces).
+ * Sequence items are denoted by a dash,
+ * key value pairs within a map are separated by a colon.
+ * </pre>
+ */
+public class ConfiguredResourcesModelProviderSpi implements ModelProviderSpi {
+
+ /**
+ * The logger.
+ */
+ private static final Logger LOG = Logger.getLogger(ConfiguredResourcesModelProviderSpi.class.getName());
+ /**
+ * The parameter that can be used to configure the location of the configuration model resources.
+ */
+ private static final String MODEL_RESOURCE_PARAM = "org.apache.tamaya.model.resources";
+ /**
+ * The resource class to checked for testing the availability of the resources extension module.
+ */
+ private static final String CONFIG_RESOURCE_CLASS = "org.apache.tamaya.resource.ConfigResource";
+ /**
+ * The resource class to checked for testing the availability of the formats extension module.
+ */
+ private static final String CONFIGURATION_FORMATS_CLASS = "org.apache.tamaya.format.ConfigurationFormats";
+ /**
+ * Initializes the flag showing if the formats module is present (required).
+ */
+ private static final boolean AVAILABLE = checkAvailabilityFormats();
+ /**
+ * Initializes the flag showing if the resources module is present (optional).
+ */
+ private static final boolean RESOURCES_EXTENSION_AVAILABLE = checkAvailabilityResources();
+
+ /**
+ * The configModels read.
+ */
+ private List<ConfigModel> configModels = new ArrayList<>();
+
+ /**
+ * Initializes the flag showing if the formats module is present (required).
+ */
+ private static boolean checkAvailabilityFormats() {
+ try {
+ Class.forName(CONFIGURATION_FORMATS_CLASS);
+ return true;
+ } catch (final Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * Initializes the flag showing if the resources module is present (optional).
+ */
+ private static boolean checkAvailabilityResources() {
+ try {
+ Class.forName(CONFIG_RESOURCE_CLASS);
+ return true;
+ } catch (final Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * Constructor, mostly called from {@link java.util.ServiceLoader}
+ */
+ public ConfiguredResourcesModelProviderSpi() {
+ if (!AVAILABLE) {
+ LOG.info("tamaya-format extension is required to read model configuration, No extended model support AVAILABLE.");
+ } else {
+ final String resources = ConfigurationProvider.getConfiguration().get(MODEL_RESOURCE_PARAM);
+ if (resources == null || resources.trim().isEmpty()) {
+ LOG.info("Mo model resources location configured in " + MODEL_RESOURCE_PARAM + ".");
+ return;
+ }
+ Collection<URL> urls;
+ if (RESOURCES_EXTENSION_AVAILABLE) {
+ LOG.info("Using tamaya-resources extension to read model configuration from " + resources);
+ urls = ConfigResources.getResourceResolver().getResources(resources.split(","));
+ } else {
+ LOG.info("Using default classloader resource location to read model configuration from " + resources);
+ urls = new ArrayList<>();
+ for (final String resource : resources.split(",")) {
+ if (!resource.trim().isEmpty()) {
+ Enumeration<URL> configs;
+ try {
+ configs = getClass().getClassLoader().getResources(resource);
+ while (configs.hasMoreElements()) {
+ urls.add(configs.nextElement());
+ }
+ } catch (final IOException e) {
+ Logger.getLogger(getClass().getName()).log(Level.SEVERE,
+ "Error evaluating config model locations from " + resource, e);
+ }
+ }
+ }
+ }
+ // Reading configs
+ for (final URL config : urls) {
+ try (InputStream is = config.openStream()) {
+ final ConfigurationData data = ConfigurationFormats.readConfigurationData(config);
+ Map<String,String> props = data.getCombinedProperties();
+ String owner = props.get("_model.provider");
+ if(owner==null){
+ owner = config.toString();
+ }
+ configModels.addAll(ConfigModelReader.loadValidations(owner, props));
+ } catch (final Exception e) {
+ Logger.getLogger(getClass().getName()).log(Level.SEVERE,
+ "Error loading config model data from " + config, e);
+ }
+ }
+ }
+ configModels = Collections.unmodifiableList(configModels);
+ }
+
+
+ @Override
+ public Collection<ConfigModel> getConfigModels() {
+ return configModels;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredTypeEventsModelPopulator.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredTypeEventsModelPopulator.java b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredTypeEventsModelPopulator.java
new file mode 100644
index 0000000..78564c3
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredTypeEventsModelPopulator.java
@@ -0,0 +1,90 @@
+/*
+ * 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.validation.internal;
+
+import org.apache.tamaya.events.ConfigEvent;
+import org.apache.tamaya.events.ConfigEventListener;
+import org.apache.tamaya.inject.spi.ConfiguredField;
+import org.apache.tamaya.inject.spi.ConfiguredMethod;
+import org.apache.tamaya.inject.spi.ConfiguredType;
+import org.apache.tamaya.validation.ConfigModelManager;
+import org.apache.tamaya.validation.spi.ParameterModel;
+
+import java.util.Collection;
+import java.util.logging.Logger;
+
+/**
+ * Internal facade that registers all kind of injected fields as {@link org.apache.tamaya.model.ConfigModel} entries,
+ * so all configured injection points are visible as documented configuration hooks.
+ */
+public final class ConfiguredTypeEventsModelPopulator implements ConfigEventListener {
+
+ /**
+ * The logger.
+ */
+ private static final Logger LOG = Logger.getLogger(ConfiguredTypeEventsModelPopulator.class.getName());
+
+ /** System property to be set to deactivate auto documentation of configured classes published thorugh
+ * ConfiguredType events.
+ */
+ private static final String ENABLE_EVENT_DOC = "org.apache.tamaya.model.autoModelEvents";
+
+ @Override
+ public void onConfigEvent(ConfigEvent event) {
+ if(event.getResourceType()!=ConfiguredType.class){
+ return;
+ }
+ String value = System.getProperty(ENABLE_EVENT_DOC);
+ if(value == null || Boolean.parseBoolean(value)) {
+ ConfiguredType confType = (ConfiguredType)event.getResource();
+ for (ConfiguredField field : confType.getConfiguredFields()) {
+ Collection<String> keys = field.getConfiguredKeys();
+ for (String key : keys) {
+ ParameterModel val = ConfigModelManager.getModel(key, ParameterModel.class);
+ if (val == null) {
+ ConfiguredTypeEventsModelProvider.addConfigModel(
+ new ParameterModel.Builder(confType.getName(), key)
+ .setType(field.getType().getName())
+ .setDescription("Injected field: " +
+ field.getAnnotatedField().getDeclaringClass().getName() + '.' + field.toString() +
+ ", \nconfigured with keys: " + keys)
+ .build());
+ }
+ }
+ }
+ for (ConfiguredMethod method : confType.getConfiguredMethods()) {
+ Collection<String> keys = method.getConfiguredKeys();
+ for (String key : keys) {
+ ParameterModel val = ConfigModelManager.getModel(key, ParameterModel.class);
+ if (val == null) {
+ ConfiguredTypeEventsModelProvider.addConfigModel(
+ new ParameterModel.Builder(confType.getName(), key)
+ .setType(method.getParameterTypes()[0].getName())
+ .setDescription("Injected field: " +
+ method.getAnnotatedMethod().getDeclaringClass().getName() + '.' + method.toString() +
+ ", \nconfigured with keys: " + keys)
+ .build());
+ }
+ }
+ }
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredTypeEventsModelProvider.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredTypeEventsModelProvider.java b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredTypeEventsModelProvider.java
new file mode 100644
index 0000000..82bd925
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/internal/ConfiguredTypeEventsModelProvider.java
@@ -0,0 +1,51 @@
+/*
+ * 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.validation.internal;
+
+import org.apache.tamaya.validation.ConfigModel;
+import org.apache.tamaya.validation.spi.ModelProviderSpi;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Model provider that adds model definitions for the items published as
+ * {@link org.apache.tamaya.inject.spi.ConfiguredType} events.
+ */
+public class ConfiguredTypeEventsModelProvider implements ModelProviderSpi {
+ /** The collected models. */
+ private static Collection<ConfigModel> configModels = new ArrayList<>();
+
+ /**
+ * Adds a model, called from the registered listener class.
+ * @param configModel adds the config model.
+ */
+ static void addConfigModel(ConfigModel configModel){
+ List<ConfigModel> newList = new ArrayList<>(configModels);
+ newList.add(configModel);
+ ConfiguredTypeEventsModelProvider.configModels = newList;
+ }
+
+ @Override
+ public Collection<ConfigModel> getConfigModels() {
+ return Collections.unmodifiableCollection(configModels);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/spi/AbstractConfigModel.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/spi/AbstractConfigModel.java b/validation/src/main/java/org/apache/tamaya/validation/spi/AbstractConfigModel.java
new file mode 100644
index 0000000..31c2395
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/spi/AbstractConfigModel.java
@@ -0,0 +1,88 @@
+/*
+ * 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.validation.spi;
+
+import org.apache.tamaya.validation.ConfigModel;
+
+import java.util.Objects;
+
+/**
+ * Default configuration Model for a configuration area.
+ */
+public abstract class AbstractConfigModel implements ConfigModel, Comparable<ConfigModel> {
+ private final String owner;
+ private final String name;
+ private final String description;
+ private boolean required = false;
+
+
+ protected AbstractConfigModel(String owner, String name, boolean required, String description) {
+ this.name = Objects.requireNonNull(name);
+ this.owner = Objects.requireNonNull(owner);
+ this.description = description;
+ this.required = required;
+ }
+
+ @Override
+ public String getOwner() {
+ return owner;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public boolean isRequired() {
+ return required;
+ }
+
+ @Override
+ public int compareTo(ConfigModel configModel) {
+ int compare = getType().compareTo(configModel.getType());
+ if (compare != 0) {
+ return compare;
+ }
+ return getName().compareTo(configModel.getName());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ AbstractConfigModel that = (AbstractConfigModel) o;
+ return getType().equals(that.getType()) && name.equals(that.name);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return getType().hashCode() + name.hashCode();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/spi/ConfigDocumentationMBean.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/spi/ConfigDocumentationMBean.java b/validation/src/main/java/org/apache/tamaya/validation/spi/ConfigDocumentationMBean.java
new file mode 100644
index 0000000..dbacaa2
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/spi/ConfigDocumentationMBean.java
@@ -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 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.validation.spi;
+
+import org.apache.tamaya.validation.ModelTarget;
+
+/**
+ * JMX Management bean for accessing current configuration information
+ */
+public interface ConfigDocumentationMBean {
+ /**
+ * Validates the configuration for the given context.
+ *
+ * @param showUndefined allows filtering for undefined configuration elements.
+ * @return the validation results, never null.
+ */
+ String validate(boolean showUndefined);
+
+ String getConfigurationModel();
+
+ String getConfigurationModel(ModelTarget type);
+
+ /**
+ * Find the validations by checking the validation's name using the given regular expression.
+ * @param namePattern the regular expression to use, not null.
+ * @return the sections defined, never null.
+ */
+ String findConfigurationModels(String namePattern);
+
+ /**
+ * Find the validations by checking the validation's name using the given regular expression.
+ * @param type the target ModelTypes (optional), not null.
+ * @param namePattern the regular expression to use, not null.
+ * @return the sections defined, never null.
+ */
+ String findValidationModels(String namePattern, ModelTarget... type);
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/spi/ConfigModelReader.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/spi/ConfigModelReader.java b/validation/src/main/java/org/apache/tamaya/validation/spi/ConfigModelReader.java
new file mode 100644
index 0000000..a9c23eb
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/spi/ConfigModelReader.java
@@ -0,0 +1,144 @@
+/*
+ * 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.validation.spi;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tamaya.validation.ConfigModel;
+
+/**
+ * Utility class to read metamodel information from properties. Hereby these properties can be part of a
+ * configuration (containing other entriees as well) or be dedicated model definition properties read
+ * from any kind of source.
+ */
+public final class ConfigModelReader {
+
+ /** The default model entries selector. */
+ private static final String DEFAULT_META_INFO_SELECTOR = ".model";
+ /** parameter to change the selector to be used for filtering out the target values to be used. */
+ private static final String META_INFO_SELECTOR_PARAM = "org.apache.tamaya.model.integrated.selector";
+
+ /**
+ * Utility class only.
+ */
+ private ConfigModelReader(){}
+
+
+ /**
+ * Loads validations as configured in the given properties.
+ * @param owner owner, not null.
+ * @param props the properties to be read
+ * @return a collection of config validations.
+ */
+ public static Collection<ConfigModel> loadValidations(String owner, Map<String,String> props) {
+ List<ConfigModel> result = new ArrayList<>();
+ Set<String> itemKeys = new HashSet<>();
+ for (Object key : props.keySet()) {
+ if (key.toString().startsWith("_") &&
+ key.toString().endsWith(DEFAULT_META_INFO_SELECTOR + ".target")) {
+ itemKeys.add(key.toString().substring(0, key.toString().length() - ".model.target".length()));
+ }
+ }
+ for (String baseKey : itemKeys) {
+ String target = props.get(baseKey + ".model.target");
+ String type = props.get(baseKey + ".model.type");
+ if (type == null) {
+ type = String.class.getName();
+ }
+ String value = props.get(baseKey + ".model.transitive");
+ boolean transitive = false;
+ if(value!=null) {
+ transitive = Boolean.parseBoolean(value);
+ }
+ String description = props.get(baseKey + ".model.description");
+ String regEx = props.get(baseKey + ".model.expression");
+ String validations = props.get(baseKey + ".model.validations");
+ String requiredVal = props.get(baseKey + ".model.required");
+ String targetKey = baseKey.substring(1);
+ if ("Parameter".equalsIgnoreCase(target)) {
+ result.add(createParameterValidation(owner, targetKey,
+ description, type, requiredVal, regEx, validations));
+ } else if ("Section".equalsIgnoreCase(target)) {
+ if(transitive){
+ result.add(createSectionValidation(owner, targetKey+".*",
+ description, requiredVal, validations));
+ } else {
+ result.add(createSectionValidation(owner, targetKey,
+ description, requiredVal, validations));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates a parameter validation.
+ * @param paramName the param name, not null.
+ * @param description the optional description
+ * @param type the param type, default is String.
+ * @param reqVal the required value, default is 'false'.
+ * @param regEx an optional regular expression to be checked for this param
+ * @param validations the optional custom validations to be performed.
+ * @return the new validation for this parameter.
+ */
+ private static ConfigModel createParameterValidation(String owner, String paramName, String description, String type, String reqVal,
+ String regEx, String validations) {
+ boolean required = "true".equalsIgnoreCase(reqVal);
+ ParameterModel.Builder builder = ParameterModel.builder(owner, paramName).setRequired(required)
+ .setDescription(description).setExpression(regEx).setType(type);
+// if (validations != null) {
+// try {
+// // TODO define validator API
+//// builder.addValidations(loadValidations(validations));
+// } catch (Exception e) {
+// LOGGER.log(Level.WARNING, "Failed to load validations for " + paramName, e);
+// }
+// }
+ return builder.build();
+ }
+
+ /**
+ * Creates a section validation.
+ * @param sectionName the section's name, not null.
+ * @param description the optional description
+ * @param reqVal the required value, default is 'false'.
+ * @param validations the optional custom validations to be performed.
+ * @return the new validation for this section.
+ */
+ private static ConfigModel createSectionValidation(String owner, String sectionName, String description, String reqVal,
+ String validations) {
+ boolean required = "true".equalsIgnoreCase(reqVal);
+ SectionModel.Builder builder = SectionModel.builder(owner, sectionName).setRequired(required)
+ .setDescription(description);
+// if (validations != null) {
+// try {
+// // TODO define validator API
+//// builder.addValidations(loadValidations(valiadtions));
+// } catch (Exception e) {
+// LOGGER.log(Level.WARNING, "Failed to load validations for " + sectionName, e);
+// }
+// }
+ return builder.build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/spi/GroupModel.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/spi/GroupModel.java b/validation/src/main/java/org/apache/tamaya/validation/spi/GroupModel.java
new file mode 100644
index 0000000..7266db7
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/spi/GroupModel.java
@@ -0,0 +1,110 @@
+/*
+ * 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.validation.spi;
+
+import org.apache.tamaya.Configuration;
+import org.apache.tamaya.validation.ConfigModel;
+import org.apache.tamaya.validation.ModelTarget;
+import org.apache.tamaya.validation.Validation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Default configuration Model for a configuration area.
+ */
+public class GroupModel implements ConfigModel {
+
+ private final String owner;
+ private final String name;
+ private boolean required;
+ private List<ConfigModel> childModels = new ArrayList<>();
+
+ public GroupModel(String owner, String name, ConfigModel... configModels){
+ this(owner, name, Arrays.asList(configModels));
+ }
+
+ public GroupModel(String owner, String name, Collection<ConfigModel> configModels){
+ this.owner = Objects.requireNonNull(owner);
+ this.name = Objects.requireNonNull(name);
+ this.childModels.addAll(configModels);
+ this.childModels = Collections.unmodifiableList(childModels);
+ for(ConfigModel val: configModels) {
+ if(val.isRequired()){
+ this.required = true;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public String getOwner() {
+ return owner;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isRequired() {
+ return required;
+ }
+
+ @Override
+ public ModelTarget getType() {
+ return ModelTarget.Group;
+ }
+
+ @Override
+ public String getDescription() {
+ if(childModels.isEmpty()){
+ return null;
+ }
+ StringBuilder b = new StringBuilder();
+ for(ConfigModel val: childModels){
+ b.append(" >> ").append(val);
+ }
+ return b.toString();
+ }
+
+ public Collection<ConfigModel> getValidations(){
+ return childModels;
+ }
+
+ @Override
+ public Collection<Validation> validate(Configuration config) {
+ List<Validation> result = new ArrayList<>(1);
+ for(ConfigModel child: childModels){
+ result.addAll(child.validate(config));
+ }
+ return result;
+ }
+
+ @Override
+ public String toString(){
+ return String.valueOf(getType()) + ", size: " + childModels.size() + ": " + getDescription();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-tamaya-sandbox/blob/041f5998/validation/src/main/java/org/apache/tamaya/validation/spi/ModelProviderSpi.java
----------------------------------------------------------------------
diff --git a/validation/src/main/java/org/apache/tamaya/validation/spi/ModelProviderSpi.java b/validation/src/main/java/org/apache/tamaya/validation/spi/ModelProviderSpi.java
new file mode 100644
index 0000000..9e2a4d4
--- /dev/null
+++ b/validation/src/main/java/org/apache/tamaya/validation/spi/ModelProviderSpi.java
@@ -0,0 +1,39 @@
+/*
+ * 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.validation.spi;
+
+import org.apache.tamaya.validation.ConfigModel;
+
+import java.util.Collection;
+
+/**
+ * Model of a configuration state. A model can be a full model, or a partial model, validating only
+ * a configuration subset. This allows better user feedback because big configurations can be grouped
+ * and validated by multiple (partial) models.
+ */
+public interface ModelProviderSpi {
+
+ /**
+ * Get the validation defined.
+ *
+ * @return the sections defined, never null.
+ */
+ Collection<ConfigModel> getConfigModels();
+
+}