You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2020/11/13 08:05:07 UTC

[sling-org-apache-sling-feature-extension-apiregions] branch SLING-9867 updated: Start implementing merge handler, add region support

This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch SLING-9867
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-extension-apiregions.git


The following commit(s) were added to refs/heads/SLING-9867 by this push:
     new 803b114  Start implementing merge handler, add region support
803b114 is described below

commit 803b1145ea8bd255158bbe515ce6a5c041e71cdd
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Nov 13 09:04:03 2020 +0100

    Start implementing merge handler, add region support
---
 .../apiregions/ConfigurationApiMergeHandler.java   |  48 +++++++++
 .../apiregions/api/config/ConfigurationApi.java    |  57 +++++++++-
 .../apiregions/api/config/InternalConstants.java   |   2 +
 .../extension/apiregions/api/config/Region.java    |  24 +++++
 .../org.apache.sling.feature.builder.MergeHandler  |   1 +
 .../ConfigurationApiMergeHandlerTest.java          | 115 +++++++++++++++++++++
 .../api/config/ConfigurationApiTest.java           |  27 ++++-
 ...pertyTest.java => PropertyDescriptionTest.java} |   2 +-
 8 files changed, 271 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandler.java b/src/main/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandler.java
index 7c83c71..b7d6b68 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandler.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandler.java
@@ -16,12 +16,18 @@
  */
 package org.apache.sling.feature.extension.apiregions;
 
+import java.util.Map;
+
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.builder.HandlerContext;
 import org.apache.sling.feature.builder.MergeHandler;
 import org.apache.sling.feature.extension.apiregions.api.config.ConfigurationApi;
+import org.apache.sling.feature.extension.apiregions.api.config.ConfigurationDescription;
+import org.apache.sling.feature.extension.apiregions.api.config.FactoryConfigurationDescription;
+import org.apache.sling.feature.extension.apiregions.api.config.FrameworkPropertyDescription;
+import org.apache.sling.feature.extension.apiregions.api.config.Region;
 
 /**
  * Merge the configuration api extension
@@ -44,9 +50,51 @@ public class ConfigurationApiMergeHandler implements MergeHandler {
             // no target available yet, just copy source
             final Extension ext = new Extension(ExtensionType.JSON, ConfigurationApi.EXTENSION_NAME, sourceExtension.getState());
             ext.setJSON(sourceExtension.getJSON());
+            targetFeature.getExtensions().add(ext);
         } else {
             final ConfigurationApi sourceApi = ConfigurationApi.getConfigurationApi(sourceExtension);
             final ConfigurationApi targetApi = ConfigurationApi.getConfigurationApi(targetExtension);
+
+            // region merging
+            if ( context.isInitialMerge() ) {
+                targetApi.setRegion(sourceApi.getRegion());
+            } else {
+                // region merging is different for prototypes
+                if ( sourceApi.getRegion() != targetApi.getRegion() ) {
+                    if ( context.isPrototypeMerge() ) {
+                        if ( sourceApi.getRegion() != null ) {
+                            targetApi.setRegion(sourceApi.getRegion());
+                        }
+                    } else {                    
+                        targetApi.setRegion(Region.GLOBAL);
+                    }
+                }
+            }
+
+            // merge - but throw on duplicates
+            for(final Map.Entry<String, ConfigurationDescription> entry : sourceApi.getConfigurationDescriptions().entrySet()) {
+                if ( targetApi.getConfigurationDescriptions().containsKey(entry.getKey())) {
+                    throw new IllegalStateException("Duplicate configuration description " + entry.getKey());
+                }
+                targetApi.getConfigurationDescriptions().put(entry.getKey(), entry.getValue());
+            }
+            for(final Map.Entry<String, FactoryConfigurationDescription> entry : sourceApi.getFactoryConfigurationDescriptions().entrySet()) {
+                if ( targetApi.getFactoryConfigurationDescriptions().containsKey(entry.getKey())) {
+                    throw new IllegalStateException("Duplicate factory configuration description " + entry.getKey());
+                }
+                targetApi.getFactoryConfigurationDescriptions().put(entry.getKey(), entry.getValue());
+            }
+            for(final Map.Entry<String, FrameworkPropertyDescription> entry : sourceApi.getFrameworkPropertyDescriptions().entrySet()) {
+                if ( targetApi.getFrameworkPropertyDescriptions().containsKey(entry.getKey())) {
+                    throw new IllegalStateException("Duplicate framework property description " + entry.getKey());
+                }
+                targetApi.getFrameworkPropertyDescriptions().put(entry.getKey(), entry.getValue());
+            }
+            targetApi.getInternalConfigurations().addAll(sourceApi.getInternalConfigurations());
+            targetApi.getInternalFactoryConfigurations().addAll(sourceApi.getInternalFactoryConfigurations());
+            targetApi.getInternalFrameworkProperties().addAll(sourceApi.getInternalFrameworkProperties());
+
+            ConfigurationApi.setConfigurationApi(targetFeature, targetApi);
         }
     }
 }
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApi.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApi.java
index 33599d8..2d7af47 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApi.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApi.java
@@ -30,6 +30,7 @@ import javax.json.JsonObjectBuilder;
 import javax.json.JsonValue;
 
 import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionState;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Feature;
 
@@ -78,6 +79,32 @@ public class ConfigurationApi extends AttributeableEntity {
         }
     }
    
+    /**
+     * Set the configuration api as an extension to the feature
+     * @param feature The feature
+     * @param api The configuration api
+     * @throws IllegalStateException If the feature has already an extension of a wrong type
+     * @throws IllegalArgumentException If the api configuration can't be serialized to JSON
+     */
+    public static void setConfigurationApi(final Feature feature, final ConfigurationApi api) {
+        Extension ext = feature.getExtensions().getByName(EXTENSION_NAME);
+        if ( api == null ) {
+            if ( ext != null ) {
+                feature.getExtensions().remove(ext);
+            }
+        } else {
+            if ( ext == null ) {
+                ext = new Extension(ExtensionType.JSON, EXTENSION_NAME, ExtensionState.OPTIONAL);
+                feature.getExtensions().add(ext);
+            }
+            try {
+                ext.setJSONStructure(api.toJSONObject());
+            } catch ( final IOException ioe) {
+                throw new IllegalArgumentException(ioe);
+            }
+        }
+    }
+
     /** The map of configurations */
  	private final Map<String, ConfigurationDescription> configurations = new LinkedHashMap<>();
 
@@ -96,6 +123,9 @@ public class ConfigurationApi extends AttributeableEntity {
     /** The list of internal framework property names */
     private final List<String> internalFrameworkProperties = new ArrayList<>();
     
+    /** The configuration region of this feature */
+    private Region region;
+
     /**
      * Clear the object and reset to defaults
      */
@@ -107,6 +137,7 @@ public class ConfigurationApi extends AttributeableEntity {
         this.internalConfigurations.clear();
         this.internalFactories.clear();
         this.internalFrameworkProperties.clear();
+        this.setRegion(null);
     }
 
 	/**
@@ -119,6 +150,11 @@ public class ConfigurationApi extends AttributeableEntity {
     public void fromJSONObject(final JsonObject jsonObj) throws IOException {
         super.fromJSONObject(jsonObj);
         try {
+			final String typeVal = this.getString(InternalConstants.KEY_REGION);
+			if ( typeVal != null ) {
+                this.setRegion(Region.valueOf(typeVal.toUpperCase()));				
+			}
+
             JsonValue val;
             val = this.getAttributes().remove(InternalConstants.KEY_CONFIGURATIONS);
             if ( val != null ) {
@@ -222,6 +258,22 @@ public class ConfigurationApi extends AttributeableEntity {
     }
 
     /**
+     * Get the api configuration region
+     * @return The region or {@code null}
+     */
+    public Region getRegion() {
+        return this.region;
+    }
+
+    /**
+     * Set the api configuration region
+     * @param value The region to set
+     */
+    public void setRegion(final Region value) {
+        this.region = value;
+    }
+
+    /**
      * Convert this object into JSON
      *
      * @return The json object builder
@@ -229,6 +281,9 @@ public class ConfigurationApi extends AttributeableEntity {
      */
     JsonObjectBuilder createJson() throws IOException {
 		final JsonObjectBuilder objBuilder = super.createJson();
+        if ( this.getRegion() != null ) {
+            objBuilder.add(InternalConstants.KEY_REGION, this.getRegion().name());
+        }
         if ( !this.getConfigurationDescriptions().isEmpty() ) {
             final JsonObjectBuilder propBuilder = Json.createObjectBuilder();
             for(final Map.Entry<String, ConfigurationDescription> entry : this.getConfigurationDescriptions().entrySet()) {
@@ -270,7 +325,7 @@ public class ConfigurationApi extends AttributeableEntity {
                 arrayBuilder.add(n);
             }
 			objBuilder.add(InternalConstants.KEY_INTERNAL_FWK_PROPERTIES, arrayBuilder);
-		}
+        }
 
 		return objBuilder;
     }
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/InternalConstants.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/InternalConstants.java
index 65922cd..2fff4a3 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/InternalConstants.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/InternalConstants.java
@@ -68,4 +68,6 @@ abstract class InternalConstants {
     static final String KEY_OPERATIONS = "operations";
 
     static final String KEY_INTERNAL_NAMES = "internal-names";
+
+    static final String KEY_REGION = "region";
 }
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/Region.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/Region.java
new file mode 100644
index 0000000..d4c14f4
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/Region.java
@@ -0,0 +1,24 @@
+/*
+ * 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.sling.feature.extension.apiregions.api.config;
+
+public enum Region {
+    
+    GLOBAL,
+    INTERNAL;
+
+}
diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.builder.MergeHandler b/src/main/resources/META-INF/services/org.apache.sling.feature.builder.MergeHandler
index ec6db93..caa2534 100644
--- a/src/main/resources/META-INF/services/org.apache.sling.feature.builder.MergeHandler
+++ b/src/main/resources/META-INF/services/org.apache.sling.feature.builder.MergeHandler
@@ -1 +1,2 @@
 org.apache.sling.feature.extension.apiregions.APIRegionMergeHandler
+org.apache.sling.feature.extension.apiregions.ConfigurationApiMergeHandler
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandlerTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandlerTest.java
new file mode 100644
index 0000000..5856910
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/ConfigurationApiMergeHandlerTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.sling.feature.extension.apiregions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.Prototype;
+import org.apache.sling.feature.builder.BuilderContext;
+import org.apache.sling.feature.builder.FeatureBuilder;
+import org.apache.sling.feature.extension.apiregions.api.config.ConfigurationApi;
+import org.apache.sling.feature.extension.apiregions.api.config.Region;
+import org.junit.Test;
+
+public class ConfigurationApiMergeHandlerTest {
+
+    @Test public void testPrototypeRegionMerge() {
+        final Feature prototype = new Feature(ArtifactId.parse("g:p:1"));
+        final ConfigurationApi prototypeApi = new ConfigurationApi();
+        ConfigurationApi.setConfigurationApi(prototype, prototypeApi);
+
+        // always return prototype
+        final BuilderContext context = new BuilderContext(id -> prototype);
+        context.addMergeExtensions(new ConfigurationApiMergeHandler());
+        
+        final Feature feature = new Feature(ArtifactId.parse("g:f:1"));
+        feature.setPrototype(new Prototype(prototype.getId()));
+        final ConfigurationApi featureApi = new ConfigurationApi();
+        ConfigurationApi.setConfigurationApi(feature, featureApi);
+
+        // no region
+        Feature result = FeatureBuilder.assemble(feature, context);
+        ConfigurationApi api = ConfigurationApi.getConfigurationApi(result);
+        assertNotNull(api);
+        assertNull(api.getRegion());
+
+        // prototype has region
+        prototypeApi.setRegion(Region.INTERNAL);
+        ConfigurationApi.setConfigurationApi(prototype, prototypeApi);
+        result = FeatureBuilder.assemble(feature, context);
+        api = ConfigurationApi.getConfigurationApi(result);
+        assertEquals(Region.INTERNAL, api.getRegion());
+
+        prototypeApi.setRegion(Region.GLOBAL);
+        ConfigurationApi.setConfigurationApi(prototype, prototypeApi);
+        result = FeatureBuilder.assemble(feature, context);
+        api = ConfigurationApi.getConfigurationApi(result);
+        assertEquals(Region.GLOBAL, api.getRegion());
+
+        // feature has region
+        prototypeApi.setRegion(null);
+        ConfigurationApi.setConfigurationApi(prototype, prototypeApi);
+        featureApi.setRegion(Region.INTERNAL);
+        ConfigurationApi.setConfigurationApi(feature, featureApi);
+        result = FeatureBuilder.assemble(feature, context);
+        api = ConfigurationApi.getConfigurationApi(result);
+        assertEquals(Region.INTERNAL, api.getRegion());
+
+        featureApi.setRegion(Region.GLOBAL);
+        ConfigurationApi.setConfigurationApi(feature, featureApi);
+        result = FeatureBuilder.assemble(feature, context);
+        api = ConfigurationApi.getConfigurationApi(result);
+        assertEquals(Region.GLOBAL, api.getRegion());
+
+        // both have region
+        prototypeApi.setRegion(Region.INTERNAL);
+        ConfigurationApi.setConfigurationApi(prototype, prototypeApi);
+        featureApi.setRegion(Region.INTERNAL);
+        ConfigurationApi.setConfigurationApi(feature, featureApi);
+        result = FeatureBuilder.assemble(feature, context);
+        api = ConfigurationApi.getConfigurationApi(result);
+        assertEquals(Region.INTERNAL, api.getRegion());
+
+        prototypeApi.setRegion(Region.GLOBAL);
+        ConfigurationApi.setConfigurationApi(prototype, prototypeApi);
+        featureApi.setRegion(Region.INTERNAL);
+        ConfigurationApi.setConfigurationApi(feature, featureApi);
+        result = FeatureBuilder.assemble(feature, context);
+        api = ConfigurationApi.getConfigurationApi(result);
+        assertEquals(Region.INTERNAL, api.getRegion());
+
+        prototypeApi.setRegion(Region.INTERNAL);
+        ConfigurationApi.setConfigurationApi(prototype, prototypeApi);
+        featureApi.setRegion(Region.GLOBAL);
+        ConfigurationApi.setConfigurationApi(feature, featureApi);
+        result = FeatureBuilder.assemble(feature, context);
+        api = ConfigurationApi.getConfigurationApi(result);
+        assertEquals(Region.GLOBAL, api.getRegion());
+
+        prototypeApi.setRegion(Region.GLOBAL);
+        ConfigurationApi.setConfigurationApi(prototype, prototypeApi);
+        featureApi.setRegion(Region.GLOBAL);
+        ConfigurationApi.setConfigurationApi(feature, featureApi);
+        result = FeatureBuilder.assemble(feature, context);
+        api = ConfigurationApi.getConfigurationApi(result);
+        assertEquals(Region.GLOBAL, api.getRegion());
+    }
+ }
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApiTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApiTest.java
index f6beac6..a362501 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApiTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/ConfigurationApiTest.java
@@ -17,6 +17,7 @@
 package org.apache.sling.feature.extension.apiregions.api.config;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -51,6 +52,20 @@ public class ConfigurationApiTest {
         ConfigurationApi.getConfigurationApi(f);
     }
 
+    @Test public void testSetConfigurationApi() {
+        final ConfigurationApi api = new ConfigurationApi();
+        final Feature f = new Feature(ArtifactId.parse("g:a:1"));
+
+        assertNull(f.getExtensions().getByName(ConfigurationApi.EXTENSION_NAME));
+
+        ConfigurationApi.setConfigurationApi(f, api);
+        assertNotNull(f.getExtensions().getByName(ConfigurationApi.EXTENSION_NAME));
+        assertNotNull(ConfigurationApi.getConfigurationApi(f));
+
+        ConfigurationApi.setConfigurationApi(f, null);
+        assertNull(f.getExtensions().getByName(ConfigurationApi.EXTENSION_NAME));
+    }
+
     @Test public void testClear() {
         final ConfigurationApi entity = new ConfigurationApi();
         entity.getAttributes().put("a", Json.createValue(5));
@@ -60,6 +75,7 @@ public class ConfigurationApiTest {
         entity.getInternalConfigurations().add("ipid");
         entity.getInternalFactoryConfigurations().add("ifactory");
         entity.getInternalFrameworkProperties().add("iprop");
+        entity.setRegion(Region.GLOBAL);
         entity.clear();
         assertTrue(entity.getAttributes().isEmpty());
         assertTrue(entity.getConfigurationDescriptions().isEmpty());
@@ -68,6 +84,7 @@ public class ConfigurationApiTest {
         assertTrue(entity.getInternalConfigurations().isEmpty());
         assertTrue(entity.getInternalFactoryConfigurations().isEmpty());
         assertTrue(entity.getInternalFrameworkProperties().isEmpty());
+        assertNull(entity.getRegion());
     }
 
     @Test public void testFromJSONObject() throws IOException {
@@ -77,7 +94,8 @@ public class ConfigurationApiTest {
             "\"framework-properties\" : { \"prop\" : { \"type\" : \"STRING\"}}," +
             "\"internal-configurations\" : [\"ipid\"],"+
             "\"internal-factory-configurations\" : [\"ifactory\"],"+
-            "\"internal-framework-properties\" : [\"iprop\"]}");
+            "\"internal-framework-properties\" : [\"iprop\"],"+
+            "\"region\" : \"INTERNAL\"}");
 
         final ConfigurationApi entity = new ConfigurationApi();
         entity.fromJSONObject(ext.getJSONStructure().asJsonObject());
@@ -93,6 +111,7 @@ public class ConfigurationApiTest {
         assertTrue(entity.getInternalConfigurations().contains("ipid"));
         assertTrue(entity.getInternalFactoryConfigurations().contains("ifactory"));
         assertTrue(entity.getInternalFrameworkProperties().contains("iprop"));
+        assertEquals(Region.INTERNAL, entity.getRegion());
     }
 
     @Test public void testToJSONObject() throws IOException {
@@ -104,6 +123,7 @@ public class ConfigurationApiTest {
         entity.getInternalConfigurations().add("ipid");
         entity.getInternalFactoryConfigurations().add("ifactory");
         entity.getInternalFrameworkProperties().add("iprop");
+        entity.setRegion(Region.INTERNAL);
 
         final Extension ext = new Extension(ExtensionType.JSON, "a", ExtensionState.OPTIONAL);
         ext.setJSON("{ \"a\" : 5, \"configurations\" : { \"pid\": {}}, " +
@@ -111,8 +131,9 @@ public class ConfigurationApiTest {
             "\"framework-properties\" : { \"prop\" : {}}," +
             "\"internal-configurations\" : [\"ipid\"],"+
             "\"internal-factory-configurations\" : [\"ifactory\"],"+
-            "\"internal-framework-properties\" : [\"iprop\"]}");
+            "\"internal-framework-properties\" : [\"iprop\"],"+
+            "\"region\" : \"INTERNAL\"}");
 
-        assertEquals(ext.getJSONStructure().asJsonObject(), entity.toJSONObject());
+        assertEquals(ext.getJSONStructure().asJsonObject(), entity.toJSONObject());        
     }
 }
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyDescriptionTest.java
similarity index 99%
rename from src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyTest.java
rename to src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyDescriptionTest.java
index 515d68d..d9b50c2 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/PropertyDescriptionTest.java
@@ -33,7 +33,7 @@ import org.apache.sling.feature.ExtensionState;
 import org.apache.sling.feature.ExtensionType;
 import org.junit.Test;
 
-public class PropertyTest {
+public class PropertyDescriptionTest {
 
     @Test public void testClear() {
         final PropertyDescription entity = new PropertyDescription();