Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 3DE3C200BB0 for ; Sun, 30 Oct 2016 18:26:04 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 3C526160AF8; Sun, 30 Oct 2016 17:26:04 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id BAED9160AF1 for ; Sun, 30 Oct 2016 18:26:01 +0100 (CET) Received: (qmail 79140 invoked by uid 500); 30 Oct 2016 17:26:00 -0000 Mailing-List: contact commits-help@tamaya.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@tamaya.incubator.apache.org Delivered-To: mailing list commits@tamaya.incubator.apache.org Received: (qmail 79131 invoked by uid 99); 30 Oct 2016 17:26:00 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd2-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 30 Oct 2016 17:26:00 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd2-us-west.apache.org (ASF Mail Server at spamd2-us-west.apache.org) with ESMTP id 52F7A1A00AA for ; Sun, 30 Oct 2016 17:26:00 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd2-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -6.219 X-Spam-Level: X-Spam-Status: No, score=-6.219 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-2.999] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd2-us-west.apache.org [10.40.0.9]) (amavisd-new, port 10024) with ESMTP id odJzJd4gbuUX for ; Sun, 30 Oct 2016 17:25:47 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with SMTP id 038435FBD4 for ; Sun, 30 Oct 2016 17:25:44 +0000 (UTC) Received: (qmail 78681 invoked by uid 99); 30 Oct 2016 17:25:44 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 30 Oct 2016 17:25:44 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E2B4CE188D; Sun, 30 Oct 2016 17:25:43 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: anatole@apache.org To: commits@tamaya.incubator.apache.org Date: Sun, 30 Oct 2016 17:25:46 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [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). archived-at: Sun, 30 Oct 2016 17:26:04 -0000 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 @@ + + + + + + + +
+ + <__description>Late afternoon is best. + Backup contact is Nancy. + + + +
+ + String + true + a required parameter + + + MyNumber + true + an optional parameter (default) + + + Integer + true + a.paramInt + +
+ Just a test section. +
+ 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 minmally documented String parameter + + + String + + + String + true + a required parameterdescription> + + + Integer + an optional parameter (default) + +
+ Just a test section. +
+
+
+ true +
+
+
+ org.apache.tamaya.model.configModel.MaxItemValidator?max=3" + A configModel section. +
+
+ 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: + *
+     *     Sections: a.b.c
+     *     Params: a.b.c.paramName
+     *     Filter: a.b.c.FilterImplClass
+     *     Dependency: mydepClassname
+     *     CombinationPolicy: a.b.c.MyCombinationPolicyClass
+     * 
+ * @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 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 models = new ArrayList<>(getModels()); + Collections.sort(models, new Comparator() { + @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 getModels() { + List 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 type of the model to filter for. + * @return the sections defined, never null. + */ + public static T getModel(String name, Class 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 findModels(String namePattern, ModelTarget... targets) { + List 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 validate() { + return validate(false); + } + + /** + * Validates the current configuration. + * @param showUndefined show any unknown parameters. + * @return the validation results, never null. + */ + public static Collection 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 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 validate(Configuration config, boolean showUndefined) { + List result = new ArrayList<>(); + for (ConfigModel defConf : getModels()) { + result.addAll(defConf.validate(config)); + } + if(showUndefined){ + Map map = new HashMap<>(config.getProperties()); + Set areas = extractTransitiveAreas(map.keySet()); + for (ConfigModel defConf : getModels()) { + if(ModelTarget.Section.equals(defConf.getType())){ + for (Iterator 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 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("", entry.getKey(), ModelTarget.Parameter)); + } + for(String area:areas){ + result.add(Validation.ofUndefined("", area, ModelTarget.Section)); + } + } + return result; + } + + private static java.util.Set extractTransitiveAreas(Set keys) { + Set 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 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 COMPARATOR = new Comparator() { + @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 VAL_COMPARATOR = new Comparator() { + @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 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 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 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 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 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():""); + } + + + 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 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 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 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: + *
+ * ###################################################################################
+ * # 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
+ * 
+ */ +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 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 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 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 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: + *
+ *  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.
+ * 
+ */ +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 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 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 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 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 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 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 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 configModels = new ArrayList<>(); + + /** + * Adds a model, called from the registered listener class. + * @param configModel adds the config model. + */ + static void addConfigModel(ConfigModel configModel){ + List newList = new ArrayList<>(configModels); + newList.add(configModel); + ConfiguredTypeEventsModelProvider.configModels = newList; + } + + @Override + public Collection 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 { + 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 loadValidations(String owner, Map props) { + List result = new ArrayList<>(); + Set 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 childModels = new ArrayList<>(); + + public GroupModel(String owner, String name, ConfigModel... configModels){ + this(owner, name, Arrays.asList(configModels)); + } + + public GroupModel(String owner, String name, Collection 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 getValidations(){ + return childModels; + } + + @Override + public Collection validate(Configuration config) { + List 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 getConfigModels(); + +}