Author: tchemit Date: 2010-11-29 00:16:57 +0100 (Mon, 29 Nov 2010) New Revision: 1015 Url: http://nuiton.org/repositories/revision/eugene/1015 Log: Evolution #1113: Introduce a safe api to manager tag values and stereotypes Added: trunk/eugene/src/main/java/org/nuiton/eugene/ModelPropertiesUtil.java trunk/eugene/src/main/resolver-cache/META-INF/services/ trunk/eugene/src/main/resolver-cache/META-INF/services/org.nuiton.eugene.ModelPropertiesUtil$ModelPropertiesProvider trunk/eugene/src/test/java/org/nuiton/eugene/EugeneModelPropertiesProviderTest.java Removed: trunk/eugene/src/main/java/org/nuiton/eugene/StereotypeDefinition.java trunk/eugene/src/main/java/org/nuiton/eugene/TagValueDefinition.java Modified: trunk/eugene/src/main/java/org/nuiton/eugene/EugeneStereoTypes.java trunk/eugene/src/main/java/org/nuiton/eugene/EugeneTagValues.java trunk/eugene/src/main/java/org/nuiton/eugene/ModelReader.java trunk/eugene/src/main/java/org/nuiton/eugene/models/object/ObjectModelReader.java trunk/maven-eugene-plugin/src/main/java/org/nuiton/eugene/plugin/writer/ModelChainedFileWriter.java Modified: trunk/eugene/src/main/java/org/nuiton/eugene/EugeneStereoTypes.java =================================================================== --- trunk/eugene/src/main/java/org/nuiton/eugene/EugeneStereoTypes.java 2010-11-28 20:13:58 UTC (rev 1014) +++ trunk/eugene/src/main/java/org/nuiton/eugene/EugeneStereoTypes.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -46,7 +46,7 @@ * @see JavaBeanTransformer * @see JavaGeneratorUtil#hasBeanStereotype(ObjectModelClassifier) */ - @StereotypeDefinition(target = ObjectModelClassifier.class) + @ModelPropertiesUtil.StereotypeDefinition(target = ObjectModelClassifier.class) String STEREOTYPE_BEAN = "bean"; /** @@ -54,6 +54,6 @@ * * @see GeneratorUtil#hasIndexedStereotype(ObjectModelAttribute) */ - @StereotypeDefinition(target = ObjectModelAttribute.class) + @ModelPropertiesUtil.StereotypeDefinition(target = ObjectModelAttribute.class) String STEREOTYPE_INDEXED = "indexed"; } Modified: trunk/eugene/src/main/java/org/nuiton/eugene/EugeneTagValues.java =================================================================== --- trunk/eugene/src/main/java/org/nuiton/eugene/EugeneTagValues.java 2010-11-28 20:13:58 UTC (rev 1014) +++ trunk/eugene/src/main/java/org/nuiton/eugene/EugeneTagValues.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -50,10 +50,10 @@ * used while reading the properties associated with a model and if found is * directly set to the {@code version} field of the model. * - * @see ObjectModelReader#loadModelTagvalue(ObjectModel, String, String) + * @see ObjectModelReader#loadModelTagValue(ObjectModel, String, String) * @since 2.3 */ - @TagValueDefinition(target = {ObjectModel.class}) + @ModelPropertiesUtil.TagValueDefinition(target = {ObjectModel.class}) String TAG_VERSION = "version"; /** @@ -65,7 +65,7 @@ * @see JavaGeneratorUtil#getConstantPrefixTagValue(ObjectModel, ObjectModelClassifier) * @since 2.3 */ - @TagValueDefinition(target = {ObjectModel.class, ObjectModelClassifier.class}) + @ModelPropertiesUtil.TagValueDefinition(target = {ObjectModel.class, ObjectModelClassifier.class}) String TAG_CONSTANT_PREFIX = "constantPrefix"; /** @@ -77,7 +77,7 @@ * @see JavaGeneratorUtil#getNoPCSTagValue(ObjectModel, ObjectModelClassifier) * @since 2.3 */ - @TagValueDefinition(target = {ObjectModel.class, ObjectModelClassifier.class}) + @ModelPropertiesUtil.TagValueDefinition(target = {ObjectModel.class, ObjectModelClassifier.class}) String TAG_NO_PCS = "noPCS"; /** @@ -88,6 +88,6 @@ * @see JavaGeneratorUtil#getI18nPrefixTagValue(ObjectModelElement, ObjectModel) * @since 2.3 */ - @TagValueDefinition(target = {ObjectModel.class, ObjectModelClassifier.class}) + @ModelPropertiesUtil.TagValueDefinition(target = {ObjectModel.class, ObjectModelClassifier.class}) String TAG_I18N_PREFIX = "i18n"; } Added: trunk/eugene/src/main/java/org/nuiton/eugene/ModelPropertiesUtil.java =================================================================== --- trunk/eugene/src/main/java/org/nuiton/eugene/ModelPropertiesUtil.java (rev 0) +++ trunk/eugene/src/main/java/org/nuiton/eugene/ModelPropertiesUtil.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -0,0 +1,259 @@ +package org.nuiton.eugene; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.TreeMap; + +/** + * Util class which introduces all the stuff to make usage of stereotype + * and tag values safe. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.3 + */ +public class ModelPropertiesUtil { + + /** Logger. */ + private static final Log log = LogFactory.getLog(ModelPropertiesUtil.class); + + /** the shared store of known tag values and stereotypes. */ + public static ModelPropertiesProvider store; + + public static Class<?>[] getTagValueTarget(String tagValueName) { + return getStore().getTagValueTarget(tagValueName); + } + + public static Class<?>[] getStereotypeTarget(String tagValueName) { + return getStore().getStereotypeTarget(tagValueName); + } + + public static ModelPropertiesProvider initStore(ClassLoader loader) { + + if (loader == null) { + + // use the current thread loader + loader = Thread.currentThread().getContextClassLoader(); + } + + store = new AggregateModelPropertiesProvider(loader); + try { + store.init(); + } catch (Exception e) { + throw new RuntimeException("Could not init store of tag values and stereotypes", e); + } + return store; + } + + public static ModelPropertiesProvider getStore() { + if (store == null) { + + store = initStore(null); + } + return store; + } + + /** + * The Eugene provider of tag values and stereotypes. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.3 + */ + public static class EugeneModelPropertiesProvider extends ModelPropertiesProvider { + + @Override + protected void init() throws IllegalAccessException { + scanStereotypeClass(EugeneStereoTypes.class); + scanTagValueClass(EugeneTagValues.class); + } + } + + /** + * A aggregate provider to box all the ones registred in the class-path via the + * {@link ServiceLoader} api. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.3 + */ + public static class AggregateModelPropertiesProvider extends ModelPropertiesProvider { + + ClassLoader loader; + + public AggregateModelPropertiesProvider(ClassLoader loader) { + this.loader = loader; + } + + @Override + protected void init() throws Exception { + ServiceLoader<ModelPropertiesProvider> loader; + loader = ServiceLoader.load(ModelPropertiesProvider.class, this.loader); + for (ModelPropertiesProvider provider : loader) { + if (log.isInfoEnabled()) { + log.info("Will init model properties provider " + provider); + } + provider.init(); + getStereotypeStore().putAll(provider.getStereotypeStore()); + getTagValueStore().putAll(provider.getTagValueStore()); + } + } + } + + /** + * To define a stereotype. + * <p/> + * Place this annotation on the constant defining your stereotype. + * <p/> + * <br/> + * Example for stereotype named mystereotype which can be only put on a attribute : + * <pre> + * String STEREOTYPE_MYSTEREOTYPE = "mystereotype"; + * \@StereotypeDefinition(target = ObjectModelAttribute.class) + * </pre + * + * @author tchemit <chemit@codelutin.com> + * @see EugeneTagValues + * @since 2.3 + */ + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + public @interface StereotypeDefinition { + + /** + * Define the types of object model api which can use this tag value. + * + * @return the array of target object model element which can accept the tag value. + */ + Class<?>[] target(); + } + + /** + * To define a tag value. + * <p/> + * Place this annotation on the constant defining your tag-value. + * <p/> + * Example for tag value named mytagvalut which can be only put on a attribute : + * <pre> + * String TAG_VALUE_MYTAGVALUE = "mytagvalue"; + * \@TagValueDefinition(target = ObjectModelAttribute.class) + * </pre + * + * @author tchemit <chemit@codelutin.com> + * @see EugeneTagValues + * @since 2.3 + */ + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + public @interface TagValueDefinition { + + /** + * Define the types of object model api which can use this tag value. + * + * @return the array of target object model element which can accept the tag value. + */ + Class<?>[] target(); + } + + /** + * TODO + * + * @author tchemit <chemit@codelutin.com> + * @since 2.3 + */ + public abstract static class ModelPropertiesProvider { + + /** Logger. */ + private static final Log log = + LogFactory.getLog(ModelPropertiesProvider.class); + + protected Map<String, TagValueDefinition> tagValueStore; + + protected ModelPropertiesProvider() { + stereotypeStore = new TreeMap<String, StereotypeDefinition>(); + tagValueStore = new TreeMap<String, TagValueDefinition>(); + } + + protected abstract void init() throws Exception; + + protected void scanStereotypeClass(Class<?> holder) throws IllegalAccessException { + if (log.isInfoEnabled()) { + log.info("Will scan " + holder.getName() + " to search some stereotype definitions..."); + } + Field[] fields = holder.getDeclaredFields(); + for (Field field : fields) { + + StereotypeDefinition stereotypeDefinition = + field.getAnnotation(StereotypeDefinition.class); + + if (stereotypeDefinition != null) { + String fieldName = field.getName(); + String stereotypeName = (String) field.get(null); + if (log.isInfoEnabled()) { + log.info("Detected stereotype definition [" + fieldName + ":" + stereotypeName + "] : " + Arrays.toString(stereotypeDefinition.target())); + } + stereotypeStore.put(stereotypeName, stereotypeDefinition); + } + } + } + + protected void scanTagValueClass(Class<?> holder) throws IllegalAccessException { + if (log.isInfoEnabled()) { + log.info("Will scan " + holder.getName() + " to search some tag value definitions..."); + } + Field[] fields = holder.getDeclaredFields(); + for (Field field : fields) { + + TagValueDefinition tagValueDefinition = + field.getAnnotation(TagValueDefinition.class); + if (tagValueDefinition != null) { + String fieldName = field.getName(); + String tagValueName = (String) field.get(null); + if (log.isInfoEnabled()) { + log.info("Detected tag value definition [" + fieldName + ":" + tagValueName + "] : " + Arrays.toString(tagValueDefinition.target())); + } + tagValueStore.put(tagValueName, tagValueDefinition); + } + } + } + + protected Map<String, StereotypeDefinition> stereotypeStore; + + protected Map<String, StereotypeDefinition> getStereotypeStore() { + return stereotypeStore; + } + + protected Map<String, TagValueDefinition> getTagValueStore() { + return tagValueStore; + } + + public Class<?>[] getTagValueTarget(String tagValueName) { + TagValueDefinition definition = tagValueStore.get(tagValueName); + + Class<?>[] result = null; + if (definition != null) { + result = definition.target(); + } + return result; + } + + public Class<?>[] getStereotypeTarget(String tagValueName) { + + StereotypeDefinition definition = stereotypeStore.get(tagValueName); + + Class<?>[] result = null; + if (definition != null) { + result = definition.target(); + } + return result; + } + + } + +} Property changes on: trunk/eugene/src/main/java/org/nuiton/eugene/ModelPropertiesUtil.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/eugene/src/main/java/org/nuiton/eugene/ModelReader.java =================================================================== --- trunk/eugene/src/main/java/org/nuiton/eugene/ModelReader.java 2010-11-28 20:13:58 UTC (rev 1014) +++ trunk/eugene/src/main/java/org/nuiton/eugene/ModelReader.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -49,6 +49,8 @@ protected long lastModifiedSource; protected boolean verbose; + + protected ClassLoader loader; public boolean isVerbose() { return verbose; @@ -58,6 +60,14 @@ this.verbose = verbose; } + public ClassLoader getLoader() { + return loader; + } + + public void setLoader(ClassLoader loader) { + this.loader = loader; + } + protected void setLastModifiedSource(File... files) { for (File file : files) { if (file.lastModified() > getLastModifiedSource()) { Deleted: trunk/eugene/src/main/java/org/nuiton/eugene/StereotypeDefinition.java =================================================================== --- trunk/eugene/src/main/java/org/nuiton/eugene/StereotypeDefinition.java 2010-11-28 20:13:58 UTC (rev 1014) +++ trunk/eugene/src/main/java/org/nuiton/eugene/StereotypeDefinition.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -1,57 +0,0 @@ -/* - * #%L - * EUGene :: EUGene - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2004 - 2010 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ -package org.nuiton.eugene; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * To define a stereotype. - * <p/> - * Place this annotation on the constant defining your stereotype. - * <p/> - * <br/> - * Example for stereotype named mystereotype which can be only put on a attribute : - * <pre> - * String STEREOTYPE_MYSTEREOTYPE = "mystereotype"; - * \@StereotypeDefinition(target = ObjectModelAttribute.class) - * </pre - * - * @author tchemit <chemit@codelutin.com> - * @see EugeneTagValues - * @since 2.3 - */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface StereotypeDefinition { - /** - * Define the types of object model api which can use this tag value. - * - * @return the array of target object model element which can accept the tag value. - */ - Class<?>[] target(); -} Deleted: trunk/eugene/src/main/java/org/nuiton/eugene/TagValueDefinition.java =================================================================== --- trunk/eugene/src/main/java/org/nuiton/eugene/TagValueDefinition.java 2010-11-28 20:13:58 UTC (rev 1014) +++ trunk/eugene/src/main/java/org/nuiton/eugene/TagValueDefinition.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -1,56 +0,0 @@ -/* - * #%L - * EUGene :: EUGene - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2004 - 2010 CodeLutin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - */ -package org.nuiton.eugene; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * To define a tag value. - * <p/> - * Place this annotation on the constant defining your tag-value. - * <p/> - * Example for tag value named mytagvalut which can be only put on a attribute : - * <pre> - * String TAG_VALUE_MYTAGVALUE = "mytagvalue"; - * \@TagValueDefinition(target = ObjectModelAttribute.class) - * </pre - * - * @author tchemit <chemit@codelutin.com> - * @see EugeneTagValues - * @since 2.3 - */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface TagValueDefinition { - /** - * Define the types of object model api which can use this tag value. - * - * @return the array of target object model element which can accept the tag value. - */ - Class<?>[] target(); -} Modified: trunk/eugene/src/main/java/org/nuiton/eugene/models/object/ObjectModelReader.java =================================================================== --- trunk/eugene/src/main/java/org/nuiton/eugene/models/object/ObjectModelReader.java 2010-11-28 20:13:58 UTC (rev 1014) +++ trunk/eugene/src/main/java/org/nuiton/eugene/models/object/ObjectModelReader.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -31,6 +31,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.eugene.EugeneTagValues; +import org.nuiton.eugene.ModelPropertiesUtil; import org.nuiton.eugene.ModelReader; import org.nuiton.eugene.models.object.xml.DigesterObjectModelRuleSet; import org.nuiton.eugene.models.object.xml.ObjectModelAssociationClassImpl; @@ -199,6 +200,9 @@ public Properties loadModelProperties(File propFile, ObjectModel model) throws IOException { + // init ModelProperties store + ModelPropertiesUtil.initStore(getLoader()); + Properties prop = new RecursiveProperties(); // try { FileInputStream inStream = new FileInputStream(propFile); @@ -207,13 +211,6 @@ } finally { inStream.close(); } -// } catch (IOException eee) { -// -// if (log.isWarnEnabled()) { -// log.warn("Impossible de lire le fichier de propriete " -// + propFile, eee); -// } -// } // number of sucessfull imported tag values into model int numberImportedTagValues = 0; @@ -235,7 +232,7 @@ // model tag value - boolean loaded = loadModelTagvalue(model, key, value); + boolean loaded = loadModelTagValue(model, key, value); if (loaded) { @@ -278,7 +275,7 @@ return prop; } - public boolean loadModelTagvalue(ObjectModel model, String key, String value) { + public boolean loadModelTagValue(ObjectModel model, String key, String value) { Matcher matcher = modelTagValuePattern.matcher(key); if (!matcher.find()) { @@ -288,6 +285,17 @@ return false; } String tag = matcher.group(2); + + Class<?>[] targets = ModelPropertiesUtil.getTagValueTarget(tag); + if (targets == null) { + + // unknown tag value, can not use it + if (log.isWarnEnabled()) { + log.warn("Invalid model tag value [" + key + "] : the tagvalue is unkown."); + } + return false; + } + ObjectModelImpl modelImpl = (ObjectModelImpl) model; if (tag.equals(EugeneTagValues.TAG_VERSION)) { Added: trunk/eugene/src/main/resolver-cache/META-INF/services/org.nuiton.eugene.ModelPropertiesUtil$ModelPropertiesProvider =================================================================== --- trunk/eugene/src/main/resolver-cache/META-INF/services/org.nuiton.eugene.ModelPropertiesUtil$ModelPropertiesProvider (rev 0) +++ trunk/eugene/src/main/resolver-cache/META-INF/services/org.nuiton.eugene.ModelPropertiesUtil$ModelPropertiesProvider 2010-11-28 23:16:57 UTC (rev 1015) @@ -0,0 +1 @@ +org.nuiton.eugene.ModelPropertiesUtil$EugeneModelPropertiesProvider \ No newline at end of file Property changes on: trunk/eugene/src/main/resolver-cache/META-INF/services/org.nuiton.eugene.ModelPropertiesUtil$ModelPropertiesProvider ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/eugene/src/test/java/org/nuiton/eugene/EugeneModelPropertiesProviderTest.java =================================================================== --- trunk/eugene/src/test/java/org/nuiton/eugene/EugeneModelPropertiesProviderTest.java (rev 0) +++ trunk/eugene/src/test/java/org/nuiton/eugene/EugeneModelPropertiesProviderTest.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -0,0 +1,57 @@ +package org.nuiton.eugene; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.nuiton.eugene.models.object.ObjectModel; +import org.nuiton.eugene.models.object.ObjectModelAttribute; +import org.nuiton.eugene.models.object.ObjectModelClassifier; + +/** + * To test {@link ModelPropertiesUtil.EugeneModelPropertiesProvider}. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.3 + */ +public class EugeneModelPropertiesProviderTest { + + protected ModelPropertiesUtil.ModelPropertiesProvider provider; + + @BeforeClass + public void setUp() { + provider = new ModelPropertiesUtil.EugeneModelPropertiesProvider(); + } + + @Test + public void testGetTagValueTarget() throws Exception { + testTagValue(EugeneTagValues.TAG_CONSTANT_PREFIX, ObjectModel.class, ObjectModelClassifier.class); + testTagValue(EugeneTagValues.TAG_I18N_PREFIX, ObjectModel.class, ObjectModelClassifier.class); + testTagValue(EugeneTagValues.TAG_NO_PCS, ObjectModel.class, ObjectModelClassifier.class); + testTagValue(EugeneTagValues.TAG_VERSION, ObjectModel.class); + } + + @Test + public void testGetStereotypeTarget() throws Exception { + + testStereotype(EugeneStereoTypes.STEREOTYPE_BEAN, ObjectModelClassifier.class); + testStereotype(EugeneStereoTypes.STEREOTYPE_INDEXED, ObjectModelAttribute.class); + } + + @Test + public void testGetStore() throws Exception { + } + + protected void testStereotype(String name, Class<?>... expected) { + Class<?>[] classes = provider.getStereotypeTarget(name); + Assert.assertNotNull("Could not find target for " + name, classes); + Assert.assertEquals("Should have " + expected.length + " targets for " + name + " but had " + classes.length, classes.length, expected.length); + Assert.assertArrayEquals(expected, classes); + } + + protected void testTagValue(String name, Class<?>... expected) { + Class<?>[] classes = provider.getTagValueTarget(name); + Assert.assertNotNull("Could not find target for " + name, classes); + Assert.assertEquals("Should have " + expected.length + " targets for " + name + " but had " + classes.length, classes.length, expected.length); + Assert.assertArrayEquals(expected, classes); + } +} Property changes on: trunk/eugene/src/test/java/org/nuiton/eugene/EugeneModelPropertiesProviderTest.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/maven-eugene-plugin/src/main/java/org/nuiton/eugene/plugin/writer/ModelChainedFileWriter.java =================================================================== --- trunk/maven-eugene-plugin/src/main/java/org/nuiton/eugene/plugin/writer/ModelChainedFileWriter.java 2010-11-28 20:13:58 UTC (rev 1014) +++ trunk/maven-eugene-plugin/src/main/java/org/nuiton/eugene/plugin/writer/ModelChainedFileWriter.java 2010-11-28 23:16:57 UTC (rev 1015) @@ -281,6 +281,7 @@ } getModelReader().setVerbose(configuration.isVerbose()); + getModelReader().setLoader(configuration.getClassLoader()); // read memory model from all files models Model model = getModelReader().read(filesToRead);