Torwards C# compatibility

* Add consistent AASDescriptor and SubmodelDescriptor
* Add endpoint to AAS
* Add Description to Referable
* Rename qualifier to constraints
* Rename key to keys
* Adds AAS constructor that creates a set of SubmodelDescriptors as
submodels
* Remove tomcat target runtime causing path errors

Signed-off-by: Patrick Pschorn <patrick.pschorn@iese.fraunhofer.de>
diff --git a/components/basys.components/.settings/org.eclipse.wst.common.project.facet.core.xml b/components/basys.components/.settings/org.eclipse.wst.common.project.facet.core.xml
index 3c2e2a0..722699b 100644
--- a/components/basys.components/.settings/org.eclipse.wst.common.project.facet.core.xml
+++ b/components/basys.components/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -1,11 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <faceted-project>

-	<runtime name="Apache Tomcat v9.0" />

-	<fixed facet="wst.jsdt.web" />

-	<fixed facet="jst.web" />

-	<fixed facet="java" />

-	<installed facet="java" version="1.8" />

-	<installed facet="jst.web" version="3.1" />

-	<installed facet="wst.jsdt.web" version="1.0" />

-	<installed facet="jst.jaxrs" version="2.0" />

+  <fixed facet="wst.jsdt.web"/>

+  <fixed facet="jst.web"/>

+  <fixed facet="java"/>

+  <installed facet="java" version="1.8"/>

+  <installed facet="jst.web" version="3.1"/>

+  <installed facet="wst.jsdt.web" version="1.0"/>

+  <installed facet="jst.jaxrs" version="2.0"/>

 </faceted-project>

diff --git a/components/basys.components/src/org/eclipse/basyx/components/proxy/registry/AASHTTPRegistryProxy.java b/components/basys.components/src/org/eclipse/basyx/components/proxy/registry/AASHTTPRegistryProxy.java
index 8549c7c..7b9c076 100644
--- a/components/basys.components/src/org/eclipse/basyx/components/proxy/registry/AASHTTPRegistryProxy.java
+++ b/components/basys.components/src/org/eclipse/basyx/components/proxy/registry/AASHTTPRegistryProxy.java
@@ -3,6 +3,7 @@
 import java.net.URLEncoder;

 import java.util.Map;

 

+import org.eclipse.basyx.aas.backend.connector.JSONConnector;

 import org.eclipse.basyx.aas.backend.http.tools.GSONTools;

 import org.eclipse.basyx.aas.backend.http.tools.factory.DefaultTypeFactory;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.identifier.IdentifierType;

@@ -98,10 +99,16 @@
 	@Override @SuppressWarnings("unchecked")

 	public AASDescriptor lookupAAS(ModelUrn aasID) {

 		// Lookup AAS from AAS directory, get AAS descriptor

-		String jsonData = client.get(aasRegistryURL+"/api/v1/registry/"+aasID.getEncodedURN());

+		String jsonResponse = client.get(aasRegistryURL+"/api/v1/registry/"+aasID.getEncodedURN());

 		

 		// Deserialize AAS descriptor

-		AASDescriptor aasDescriptor = new AASDescriptor((Map<String, Object>) serializer.deserialize(jsonData));

+		AASDescriptor aasDescriptor = null;

+		try {

+			aasDescriptor = new AASDescriptor((Map<String, Object>) (new JSONConnector(null).verify(jsonResponse)));

+		} catch (Exception e) {

+			// TODO Auto-generated catch block

+			e.printStackTrace();

+		}

 		

 		// Return AAS descriptor

 		return aasDescriptor;

diff --git a/components/basys.components/src/org/eclipse/basyx/tools/aas/connManager/AASConnectionManager.java b/components/basys.components/src/org/eclipse/basyx/tools/aas/connManager/AASConnectionManager.java
index 1df0b71..2750f2a 100644
--- a/components/basys.components/src/org/eclipse/basyx/tools/aas/connManager/AASConnectionManager.java
+++ b/components/basys.components/src/org/eclipse/basyx/tools/aas/connManager/AASConnectionManager.java
@@ -67,7 +67,7 @@
 		System.out.println("ATTEMPT:"+serializedAASDesc);

 		

 		// Deserialize AAS descriptor

-		AASDescriptor aasDescriptor = new AASDescriptor((Map<String, Object>) serializer.deserialize(serializer.getMap(serializer.getObjFromJsonStr(serializedAASDesc))));

+		AASDescriptor aasDescriptor = new AASDescriptor(((Map<String, Object>) (serializer.deserialize(serializedAASDesc))));

 

 		// Get AAD address from AAS descriptor

 		String addr = aasDescriptor.getFirstEndpoint();

@@ -88,7 +88,7 @@
 		String serializedAASDesc = directoryService.lookup(aasUrn.getEncodedURN());

 		

 		// Deserialize AAS descriptor

-		AASDescriptor aasDescriptor = new AASDescriptor((Map<String, Object>) serializer.deserialize(serializer.getMap(serializer.getObjFromJsonStr(serializedAASDesc))));

+		AASDescriptor aasDescriptor = new AASDescriptor(((Map<String, Object>) (serializer.deserialize(serializedAASDesc))));

 

 		// Locate sub model

 		SubmodelDescriptor smdescr = aasDescriptor.getSubModelDescriptor(subModelID);

diff --git a/components/basys.components/src/org/eclipse/basyx/tools/aasdescriptor/AASDescriptor.java b/components/basys.components/src/org/eclipse/basyx/tools/aasdescriptor/AASDescriptor.java
index ed54021..07c5394 100644
--- a/components/basys.components/src/org/eclipse/basyx/tools/aasdescriptor/AASDescriptor.java
+++ b/components/basys.components/src/org/eclipse/basyx/tools/aasdescriptor/AASDescriptor.java
@@ -1,11 +1,16 @@
 package org.eclipse.basyx.tools.aasdescriptor;

 

+import java.util.Arrays;

 import java.util.Collection;

 import java.util.HashMap;

+import java.util.HashSet;

 import java.util.LinkedList;

 import java.util.List;

 import java.util.Map;

 

+import org.eclipse.basyx.aas.metamodel.hashmap.VABModelMap;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.AssetAdministrationShell;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.SubModel;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.identifier.Identifier;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.identifier.IdentifierType;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.parts.Asset;

@@ -60,6 +65,32 @@
 		((Identifier) get("identification")).setId(id);

 		((List<String>) get("endpoints")).add(endpoint);

 	}

+	

+	/**

+	 * Create a new sub model descriptor with minimal information

+	 */

+	@SuppressWarnings("unchecked")

+	public AASDescriptor(AssetAdministrationShell aas, String endpoint, String endpointType) {

+		// Invoke default constructor

+		

+		

+		put("idShort", aas.getId());

+		put("submodels", new LinkedList<SubmodelDescriptor>());

+		

+		// Add identification and end point information

+		Identifier identifier =  new Identifier();

+		

+		identifier.setIdType(aas.getIdentification().getIdType());

+		identifier.setId(aas.getIdentification().getId());

+		put("identification", identifier);

+		

+		HashMap<String, String> endpointWrapper = new HashMap<String, String>(); 

+		endpointWrapper.put("type", endpointType);

+		endpointWrapper.put("address", endpoint + "/aas");

+		

+		put("endpoints", Arrays.asList(endpointWrapper));

+	}

+	

 

 	

 	/**

@@ -106,7 +137,19 @@
 	 */

 	@SuppressWarnings("unchecked")

 	public String getFirstEndpoint() {

-		return ((List<String>) get("endpoints")).get(0);

+		

+		Object e = get("endpoints");

+		// Extract String from endpoint in set and list representation

+		String endpoint = null;

+		if (e instanceof List<?>) {

+			endpoint = ((List<String>) e).get(0);

+		} else if (e instanceof HashSet<?>) {

+			endpoint = (String) ((HashSet<VABModelMap>) e).iterator().next().getPath("address");

+		} else {

+			endpoint = "not found";

+		}

+		

+		return endpoint;

 	}

 	

 	

diff --git a/components/basys.components/src/org/eclipse/basyx/tools/aasdescriptor/SubmodelDescriptor.java b/components/basys.components/src/org/eclipse/basyx/tools/aasdescriptor/SubmodelDescriptor.java
index f2b304b..b876480 100644
--- a/components/basys.components/src/org/eclipse/basyx/tools/aasdescriptor/SubmodelDescriptor.java
+++ b/components/basys.components/src/org/eclipse/basyx/tools/aasdescriptor/SubmodelDescriptor.java
@@ -1,10 +1,12 @@
 package org.eclipse.basyx.tools.aasdescriptor;

 

+import java.util.Arrays;

 import java.util.HashMap;

 import java.util.LinkedList;

 import java.util.List;

 import java.util.Map;

 

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.SubModel;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.identifier.Identifier;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier.AdministrativeInformation;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier.haskind.Kind;

@@ -59,6 +61,28 @@
 		((List<String>) get("endpoints")).add(endpoint);

 	}

 	

+	/**

+	 * Create a new sub model descriptor with minimal information

+	 */

+	@SuppressWarnings("unchecked")

+	public SubmodelDescriptor(SubModel submodel, String endpoint, String endpointType) {

+		// Invoke default constructor

+		//this();

+		

+		put("idShort", submodel.getId());

+		

+		// Add identification and end point information

+		Identifier identifier = new Identifier();

+		identifier.setIdType(submodel.getIdentification().getIdType());

+		identifier.setId(submodel.getIdentification().getId());

+		put("identification", identifier);

+		

+		HashMap<String, String> endpointWrapper = new HashMap<String, String>(); 

+		endpointWrapper.put("type", endpointType);

+		endpointWrapper.put("address", endpoint);

+		

+		put("endpoints", Arrays.asList(endpointWrapper));

+	}

 	

 	/**

 	 * Create sub model descriptor from existing hash map

diff --git a/components/basys.components/src/org/eclipse/basyx/tools/webserviceclient/WebServiceRawClient.java b/components/basys.components/src/org/eclipse/basyx/tools/webserviceclient/WebServiceRawClient.java
index 64483e3..d36c5c4 100644
--- a/components/basys.components/src/org/eclipse/basyx/tools/webserviceclient/WebServiceRawClient.java
+++ b/components/basys.components/src/org/eclipse/basyx/tools/webserviceclient/WebServiceRawClient.java
@@ -80,7 +80,7 @@
 		Response rsp = request.put(Entity.entity(jsonParameter.toString(), MediaType.APPLICATION_JSON));

 

 		// Throw exception that indicates an error

-		if (!((rsp.getStatus() == 0) || (rsp.getStatus() == 200))) throw new ServerErrorException(rsp);

+		if (!((rsp.getStatus() == 0) || (rsp.getStatus() == 200)  || (rsp.getStatus() == 201))) throw new ServerErrorException(rsp);

 

 		// Return result

 		return rsp.readEntity(String.class);

@@ -99,7 +99,7 @@
 		Response rsp = request.post(Entity.entity(jsonParameter.toString(), MediaType.APPLICATION_JSON));

 

 		// Throw exception that indicates an error

-		if (!((rsp.getStatus() == 0) || (rsp.getStatus() == 200))) throw new ServerErrorException(rsp);

+		if (!((rsp.getStatus() == 0) || (rsp.getStatus() == 200) || (rsp.getStatus() == 201))) throw new ServerErrorException(rsp);

 		

 		// Return result

 		return rsp.readEntity(String.class);

@@ -115,7 +115,7 @@
 		Response rsp = client.target(wsURL).queryParam("action", action).request().build("PATCH", Entity.text(jsonParameter.toString())).property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true).invoke();

 

 		// Throw exception that indicates an error

-		if (!((rsp.getStatus() == 0) || (rsp.getStatus() == 200))) throw new ServerErrorException(rsp);

+		if (!((rsp.getStatus() == 0) || (rsp.getStatus() == 200)  || (rsp.getStatus() == 201))) throw new ServerErrorException(rsp);

 

 		// Return result

 		return rsp.readEntity(String.class);

diff --git a/examples/basys.examples/.settings/org.eclipse.wst.common.project.facet.core.xml b/examples/basys.examples/.settings/org.eclipse.wst.common.project.facet.core.xml
index 87691af..722699b 100644
--- a/examples/basys.examples/.settings/org.eclipse.wst.common.project.facet.core.xml
+++ b/examples/basys.examples/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>

 <faceted-project>

-  <runtime name="Apache Tomcat v9.0"/>

   <fixed facet="wst.jsdt.web"/>

   <fixed facet="jst.web"/>

   <fixed facet="java"/>

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/backend/connected/aas/ConnectedAssetAdministrationShell.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/backend/connected/aas/ConnectedAssetAdministrationShell.java
index 1a04771..a71f55e 100644
--- a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/backend/connected/aas/ConnectedAssetAdministrationShell.java
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/backend/connected/aas/ConnectedAssetAdministrationShell.java
@@ -1,192 +1,192 @@
-package org.eclipse.basyx.aas.backend.connected.aas;
-
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.basyx.aas.api.metamodel.aas.identifier.IIdentifier;
-import org.eclipse.basyx.aas.api.metamodel.aas.parts.IConceptDictionary;
-import org.eclipse.basyx.aas.api.metamodel.aas.parts.IView;
-import org.eclipse.basyx.aas.api.metamodel.aas.qualifier.IAdministrativeInformation;
-import org.eclipse.basyx.aas.api.metamodel.aas.reference.IReference;
-import org.eclipse.basyx.aas.api.metamodel.aas.security.ISecurity;
-import org.eclipse.basyx.aas.api.resources.IAssetAdministrationShell;
-import org.eclipse.basyx.aas.api.resources.ISubModel;
-import org.eclipse.basyx.aas.backend.connected.ConnectedVABModelMap;
-import org.eclipse.basyx.aas.backend.connected.facades.ConnectedHasDataSpecificationFacade;
-import org.eclipse.basyx.aas.backend.connected.facades.ConnectedIdentifiableFacade;
-import org.eclipse.basyx.aas.metamodel.hashmap.aas.AssetAdministrationShell;
-import org.eclipse.basyx.vab.core.VABConnectionManager;
-import org.eclipse.basyx.vab.core.proxy.VABElementProxy;
-/**
- * "Connected" implementation of IAssetAdministrationShell
- * @author rajashek
- *
- */
-public class ConnectedAssetAdministrationShell extends ConnectedVABModelMap<Object> implements IAssetAdministrationShell {
-	
-	VABConnectionManager manager;
-	
-	/**
-	 * Constructor creating a ConnectedAAS pointing to the AAS represented by proxy
-	 * and path
-	 * 
-	 * @param path
-	 * @param proxy
-	 * @param manager
-	 */
-	public ConnectedAssetAdministrationShell(String path, VABElementProxy proxy, VABConnectionManager manager) {
-		super(path, proxy);		
-		this.manager = manager;
-	}
-	
-	/**
-	 * Copy constructor, allowing to create a ConnectedAAS pointing to the same AAS
-	 * as <i>shell</i>
-	 * 
-	 * @param shell
-	 */
-	public ConnectedAssetAdministrationShell(ConnectedAssetAdministrationShell shell) {
-		super(shell.getPath(), shell.getProxy());
-		this.manager = shell.manager;
-
-	}
-	
-	@Override
-	public IAdministrativeInformation getAdministration() {
-		return new ConnectedIdentifiableFacade(getPath(),getProxy()).getAdministration();
-	}
-
-	@Override
-	public IIdentifier getIdentification() {
-		return new ConnectedIdentifiableFacade(getPath(),getProxy()).getIdentification();
-	}
-
-	@Override
-	public void setAdministration(String version, String revision) {
-		 new ConnectedIdentifiableFacade(getPath(),getProxy()).setAdministration(version, revision);
-		
-	}
-
-	@Override
-	public void setIdentification(String idType, String id) {
-		 new ConnectedIdentifiableFacade(getPath(),getProxy()).setIdentification(idType, id);
-		
-	}
-	
-	@Override
-	public HashSet<IReference> getDataSpecificationReferences() {
-		return new ConnectedHasDataSpecificationFacade(getPath(),getProxy()).getDataSpecificationReferences();
-	}
-
-	@Override
-	public void setDataSpecificationReferences(HashSet<IReference> ref) {
-		new ConnectedHasDataSpecificationFacade(getPath(),getProxy()).setDataSpecificationReferences(ref);
-		
-	}
-	
-	@Override
-	public void setSecurity(ISecurity security) {
-		getProxy().updateElementValue(constructPath(AssetAdministrationShell.SECURITY),security );
-		
-	}
-
-	@Override
-	public ISecurity getSecurity() {
-		return (ISecurity)getProxy().readElementValue(constructPath(AssetAdministrationShell.SECURITY));
-	}
-
-	@Override
-	public void setDerivedFrom(IReference derivedFrom) {
-		getProxy().updateElementValue(constructPath(AssetAdministrationShell.DERIVEDFROM),derivedFrom) ;
-		
-	}
-
-	@Override
-	public IReference getDerivedFrom() {
-		return (IReference)getProxy().readElementValue(constructPath(AssetAdministrationShell.DERIVEDFROM));
-	}
-
-	@Override
-	public void setAsset(IReference asset) {
-		getProxy().updateElementValue(constructPath(AssetAdministrationShell.ASSET),asset );
-		
-	}
-
-	@Override
-	public IReference getAsset() {
-		return (IReference)getProxy().readElementValue(constructPath(AssetAdministrationShell.ASSET));
-	}
-
-	@Override
-	public void setSubModel(Set<IReference> submodels) {
-		getProxy().updateElementValue(constructPath(AssetAdministrationShell.SUBMODEL),submodels );
-		
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public Set<IReference> getSubModel() {
-		return (Set<IReference>)getProxy().readElementValue(constructPath(AssetAdministrationShell.SUBMODEL));
-	}
-
-	@Override
-	public void setViews(Set<IView> views) {
-		getProxy().updateElementValue(constructPath(AssetAdministrationShell.VIEWS),views);
-		
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public Set<IView> getViews() {
-		return (Set<IView>)getProxy().readElementValue(constructPath(AssetAdministrationShell.VIEWS));
-	}
-
-	@Override
-	public void setConceptDictionary(Set<IConceptDictionary> dictionaries) {
-		getProxy().updateElementValue(constructPath(AssetAdministrationShell.CONCEPTDICTIONARY), dictionaries);
-		
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public Set<IConceptDictionary> getConceptDictionary() {
-		return (Set<IConceptDictionary>)getProxy().readElementValue(constructPath(AssetAdministrationShell.CONCEPTDICTIONARY));
-	}
-	
-	@Override
-	public String getId() {
-	return (String)getProxy().readElementValue(constructPath(AssetAdministrationShell.IDSHORT));
-	}
-
-	@Override
-	public void setId(String id) {
-		getProxy().updateElementValue(constructPath(AssetAdministrationShell.IDSHORT), id);
-		
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public Map<String, ISubModel> getSubModels() {
-		Set<Map<?, ?>> refs = (Set<Map<?, ?>>) getProxy().readElementValue(constructPath("submodel"));
-		Map<String, ISubModel> ret = new HashMap<>();
-		for (Map<?, ?> key : refs) {
-			String id = (String) ((Map<?, ?>) ((List<?>) key.get("key")).get(0)).get("value");
-			VABElementProxy elem = manager.connectToVABElement(id);
-			ISubModel sm = new ConnectedSubModel("/aas/submodels/" + id, elem);
-			ret.put(id, sm);
-		}
-
-		return ret;
-	}
-
-
-	@Override
-	public void addSubModel(ISubModel subModel) {
-		// TODO Auto-generated method stub
-		
-	}
-}
+package org.eclipse.basyx.aas.backend.connected.aas;

+

+

+import java.util.HashMap;

+import java.util.HashSet;

+import java.util.List;

+import java.util.Map;

+import java.util.Set;

+

+import org.eclipse.basyx.aas.api.metamodel.aas.identifier.IIdentifier;

+import org.eclipse.basyx.aas.api.metamodel.aas.parts.IConceptDictionary;

+import org.eclipse.basyx.aas.api.metamodel.aas.parts.IView;

+import org.eclipse.basyx.aas.api.metamodel.aas.qualifier.IAdministrativeInformation;

+import org.eclipse.basyx.aas.api.metamodel.aas.reference.IReference;

+import org.eclipse.basyx.aas.api.metamodel.aas.security.ISecurity;

+import org.eclipse.basyx.aas.api.resources.IAssetAdministrationShell;

+import org.eclipse.basyx.aas.api.resources.ISubModel;

+import org.eclipse.basyx.aas.backend.connected.ConnectedVABModelMap;

+import org.eclipse.basyx.aas.backend.connected.facades.ConnectedHasDataSpecificationFacade;

+import org.eclipse.basyx.aas.backend.connected.facades.ConnectedIdentifiableFacade;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.AssetAdministrationShell;

+import org.eclipse.basyx.vab.core.VABConnectionManager;

+import org.eclipse.basyx.vab.core.proxy.VABElementProxy;

+/**

+ * "Connected" implementation of IAssetAdministrationShell

+ * @author rajashek

+ *

+ */

+public class ConnectedAssetAdministrationShell extends ConnectedVABModelMap<Object> implements IAssetAdministrationShell {

+	

+	VABConnectionManager manager;

+	

+	/**

+	 * Constructor creating a ConnectedAAS pointing to the AAS represented by proxy

+	 * and path

+	 * 

+	 * @param path

+	 * @param proxy

+	 * @param manager

+	 */

+	public ConnectedAssetAdministrationShell(String path, VABElementProxy proxy, VABConnectionManager manager) {

+		super(path, proxy);		

+		this.manager = manager;

+	}

+	

+	/**

+	 * Copy constructor, allowing to create a ConnectedAAS pointing to the same AAS

+	 * as <i>shell</i>

+	 * 

+	 * @param shell

+	 */

+	public ConnectedAssetAdministrationShell(ConnectedAssetAdministrationShell shell) {

+		super(shell.getPath(), shell.getProxy());

+		this.manager = shell.manager;

+

+	}

+	

+	@Override

+	public IAdministrativeInformation getAdministration() {

+		return new ConnectedIdentifiableFacade(getPath(),getProxy()).getAdministration();

+	}

+

+	@Override

+	public IIdentifier getIdentification() {

+		return new ConnectedIdentifiableFacade(getPath(),getProxy()).getIdentification();

+	}

+

+	@Override

+	public void setAdministration(String version, String revision) {

+		 new ConnectedIdentifiableFacade(getPath(),getProxy()).setAdministration(version, revision);

+		

+	}

+

+	@Override

+	public void setIdentification(String idType, String id) {

+		 new ConnectedIdentifiableFacade(getPath(),getProxy()).setIdentification(idType, id);

+		

+	}

+	

+	@Override

+	public HashSet<IReference> getDataSpecificationReferences() {

+		return new ConnectedHasDataSpecificationFacade(getPath(),getProxy()).getDataSpecificationReferences();

+	}

+

+	@Override

+	public void setDataSpecificationReferences(HashSet<IReference> ref) {

+		new ConnectedHasDataSpecificationFacade(getPath(),getProxy()).setDataSpecificationReferences(ref);

+		

+	}

+	

+	@Override

+	public void setSecurity(ISecurity security) {

+		getProxy().updateElementValue(constructPath(AssetAdministrationShell.SECURITY),security );

+		

+	}

+

+	@Override

+	public ISecurity getSecurity() {

+		return (ISecurity)getProxy().readElementValue(constructPath(AssetAdministrationShell.SECURITY));

+	}

+

+	@Override

+	public void setDerivedFrom(IReference derivedFrom) {

+		getProxy().updateElementValue(constructPath(AssetAdministrationShell.DERIVEDFROM),derivedFrom) ;

+		

+	}

+

+	@Override

+	public IReference getDerivedFrom() {

+		return (IReference)getProxy().readElementValue(constructPath(AssetAdministrationShell.DERIVEDFROM));

+	}

+

+	@Override

+	public void setAsset(IReference asset) {

+		getProxy().updateElementValue(constructPath(AssetAdministrationShell.ASSET),asset );

+		

+	}

+

+	@Override

+	public IReference getAsset() {

+		return (IReference)getProxy().readElementValue(constructPath(AssetAdministrationShell.ASSET));

+	}

+

+	@Override

+	public void setSubModel(Set<IReference> submodels) {

+		getProxy().updateElementValue(constructPath(AssetAdministrationShell.SUBMODEL),submodels );

+		

+	}

+

+	@SuppressWarnings("unchecked")

+	@Override

+	public Set<IReference> getSubModel() {

+		return (Set<IReference>)getProxy().readElementValue(constructPath(AssetAdministrationShell.SUBMODEL));

+	}

+

+	@Override

+	public void setViews(Set<IView> views) {

+		getProxy().updateElementValue(constructPath(AssetAdministrationShell.VIEWS),views);

+		

+	}

+

+	@SuppressWarnings("unchecked")

+	@Override

+	public Set<IView> getViews() {

+		return (Set<IView>)getProxy().readElementValue(constructPath(AssetAdministrationShell.VIEWS));

+	}

+

+	@Override

+	public void setConceptDictionary(Set<IConceptDictionary> dictionaries) {

+		getProxy().updateElementValue(constructPath(AssetAdministrationShell.CONCEPTDICTIONARY), dictionaries);

+		

+	}

+

+	@SuppressWarnings("unchecked")

+	@Override

+	public Set<IConceptDictionary> getConceptDictionary() {

+		return (Set<IConceptDictionary>)getProxy().readElementValue(constructPath(AssetAdministrationShell.CONCEPTDICTIONARY));

+	}

+	

+	@Override

+	public String getId() {

+	return (String)getProxy().readElementValue(constructPath(AssetAdministrationShell.IDSHORT));

+	}

+

+	@Override

+	public void setId(String id) {

+		getProxy().updateElementValue(constructPath(AssetAdministrationShell.IDSHORT), id);

+		

+	}

+

+	@SuppressWarnings("unchecked")

+	@Override

+	public Map<String, ISubModel> getSubModels() {

+		Set<Map<?, ?>> refs = (Set<Map<?, ?>>) getProxy().readElementValue(constructPath("submodel"));

+		Map<String, ISubModel> ret = new HashMap<>();

+		for (Map<?, ?> key : refs) {

+			String id = (String) ((Map<?, ?>) ((List<?>) key.get("keys")).get(0)).get("value");

+			VABElementProxy elem = manager.connectToVABElement(id);

+			ISubModel sm = new ConnectedSubModel("/aas/submodels/" + id, elem);

+			ret.put(id, sm);

+		}

+

+		return ret;

+	}

+

+

+	@Override

+	public void addSubModel(ISubModel subModel) {

+		// TODO Auto-generated method stub

+		

+	}

+}

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/backend/provider/VABMultiSubmodelProvider.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/backend/provider/VABMultiSubmodelProvider.java
index 37d12fb..c7e3995 100644
--- a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/backend/provider/VABMultiSubmodelProvider.java
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/backend/provider/VABMultiSubmodelProvider.java
@@ -84,6 +84,26 @@
 	public VABMultiSubmodelProvider() {

 		// Do nothing

 	}

+	

+	

+

+	/**

+	 * Constructor that accepts an AAS

+	 */

+	public VABMultiSubmodelProvider(T contentProvider) {

+		// Store content provider

+		setAssetAdministrationShell(contentProvider);

+	}

+

+	

+	/**

+	 * Constructor that accepts Submodel

+	 */

+	public VABMultiSubmodelProvider(String smID, T contentProvider) {

+		// Store content provider

+		addSubmodel(smID, contentProvider);

+	}

+

 

 	/**

 	 * Set an AAS for this provider

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/AssetAdministrationShell.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/AssetAdministrationShell.java
index ee9ba4f..6637a61 100644
--- a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/AssetAdministrationShell.java
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/AssetAdministrationShell.java
@@ -1,6 +1,8 @@
 package org.eclipse.basyx.aas.metamodel.hashmap.aas;

 

+import java.util.Arrays;

 import java.util.Collections;

+import java.util.HashMap;

 import java.util.HashSet;

 import java.util.Map;

 import java.util.Set;

@@ -17,6 +19,7 @@
 import org.eclipse.basyx.aas.metamodel.facades.HasDataSpecificationFacade;

 import org.eclipse.basyx.aas.metamodel.facades.IdentifiableFacade;

 import org.eclipse.basyx.aas.metamodel.hashmap.VABModelMap;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.descriptor.SubmodelDescriptor;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.parts.ConceptDictionary;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.parts.View;

 import org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier.HasDataSpecification;

@@ -45,6 +48,7 @@
 	public static final String DERIVEDFROM ="derivedFrom";

 	public static final String ASSET="asset";

 	public static final String SUBMODEL ="submodel";

+	public static final String SUBMODELS ="submodels";

 	public static final String VIEWS="views";

 	public static final String CONCEPTDICTIONARY="conceptDictionary";

 	public static final String IDSHORT="idShort";

@@ -69,6 +73,7 @@
 		put(DERIVEDFROM, null);

 		put(ASSET, null);

 		put(SUBMODEL, new HashSet<Reference>());

+		put(SUBMODELS, new HashSet<SubmodelDescriptor>());

 		put(VIEWS, new HashSet<View>());

 		put(CONCEPTDICTIONARY, new HashSet<ConceptDictionary>());

 	}

@@ -86,7 +91,15 @@
 		put(VIEWS, views);

 		put(CONCEPTDICTIONARY, dictionaries);

 	}

-

+	

+	public void setEndpoint(String endpoint, String endpointType) {

+		HashMap<String, String> endpointWrapper = new HashMap<String, String>(); 

+		endpointWrapper.put("type", endpointType);

+		endpointWrapper.put("address", endpoint + "/aas");

+		

+		put("endpoints", Arrays.asList(endpointWrapper));

+	}

+	

 	/**

 	 * Add a submodel as reference

 	 */

@@ -95,6 +108,14 @@
 		System.out.println("adding Submodel " + subModel.getId());

 		addSubModel(subModel.getId());

 	}

+	

+	@SuppressWarnings("unchecked")

+	public void addSubModelHack(SubModel subModel, String endpoint, String endpointType) {

+		System.out.println("adding Submodel " + subModel.getId());

+		SubmodelDescriptor desc = new SubmodelDescriptor(subModel, endpoint, endpointType);

+		((Set<SubmodelDescriptor>) get(SUBMODELS)).add(desc);

+		

+	}

 

 	@SuppressWarnings("unchecked")

 	public void addSubModel(String id) {

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/descriptor/AASDescriptor.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/descriptor/AASDescriptor.java
new file mode 100644
index 0000000..ca3528c
--- /dev/null
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/descriptor/AASDescriptor.java
@@ -0,0 +1,154 @@
+package org.eclipse.basyx.aas.metamodel.hashmap.aas.descriptor;

+

+import java.util.Arrays;

+import java.util.Collection;

+import java.util.HashMap;

+import java.util.HashSet;

+import java.util.LinkedList;

+import java.util.List;

+import java.util.Map;

+

+import org.eclipse.basyx.aas.metamodel.hashmap.VABModelMap;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.AssetAdministrationShell;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.identifier.Identifier;

+

+

+/**

+ * AAS descriptor class

+ * 

+ * @author kuhn, pschorn

+ *

+ */

+public class AASDescriptor extends HashMap<String, Object> {

+

+		

+	/**

+	 * Version of serialized instances

+	 */

+	private static final long serialVersionUID = 1L;

+

+	

+	

+	/**

+	 * Create a new sub model descriptor with minimal information

+	 */

+	@SuppressWarnings("unchecked")

+	public AASDescriptor(AssetAdministrationShell aas, String endpoint, String endpointType) {

+		// Invoke default constructor

+		

+		

+		put("idShort", aas.getId());

+		put("submodels", new LinkedList<SubmodelDescriptor>());

+		

+		// Add identification and end point information

+		Identifier identifier =  new Identifier();

+		

+		identifier.setIdType(aas.getIdentification().getIdType());

+		identifier.setId(aas.getIdentification().getId());

+		put("identification", identifier);

+		

+		HashMap<String, String> endpointWrapper = new HashMap<String, String>(); 

+		endpointWrapper.put("type", endpointType);

+		endpointWrapper.put("address", endpoint + "/aas");

+		

+		put("endpoints", Arrays.asList(endpointWrapper));

+	}

+	

+	

+	

+	/**

+	 * Create AAS descriptor from existing hash map

+	 */

+	public AASDescriptor(Map<String, Object> map) {

+		// Put all elements from map into this descriptor

+		this.putAll(map);

+	}

+	

+	

+	

+	

+	/**

+	 * Return AAS ID

+	 */

+	@SuppressWarnings("unchecked")

+	public String getId() {

+		return new Identifier((Map<String, Object>) get("identification")).getId();

+	}

+	

+	

+	/**

+	 * Return AAS ID type

+	 */

+	@SuppressWarnings("unchecked")

+	public String getIdType() {

+		return new Identifier((Map<String, Object>) get("identification")).getIdType();

+	}

+

+	

+	/**

+	 * Return first AAS end point

+	 */

+	@SuppressWarnings("unchecked")

+	public String getFirstEndpoint() {

+		

+		Object e = get("endpoints");

+		// Extract String from endpoint in set and list representation

+		String endpoint = null;

+		if (e instanceof List<?>) {

+			endpoint = ((List<String>) e).get(0);

+		} else if (e instanceof HashSet<?>) {

+			endpoint = (String) ((HashSet<VABModelMap>) e).iterator().next().getPath("address");

+		} else {

+			endpoint = "not found";

+		}

+		

+		return endpoint;

+	}

+	

+	

+	/**

+	 * Add a sub model descriptor

+	 */

+	@SuppressWarnings("unchecked")

+	public AASDescriptor addSubmodelDescriptor(SubmodelDescriptor desc) {

+		// Sub model descriptors are stored in a list

+		Collection<Map<String, Object>> submodelDescriptors = (Collection<Map<String, Object>>) get("submodels");

+		

+		// Add new sub model descriptor to list

+		submodelDescriptors.add(desc);

+		

+		// Return 'this' reference

+		return this;

+	}

+	

+	

+	

+	

+	/**

+	 * Get a specific sub model descriptor

+	 */

+	@SuppressWarnings("unchecked")

+	public SubmodelDescriptor getSubModelDescriptor(String subModelId) {

+		// Sub model descriptors are stored in a list

+		Collection<Map<String, Object>> submodelDescriptorMaps = (Collection<Map<String, Object>>) get("submodels");

+

+		System.out.println("Checking submodel desc");

+

+		// Create sub model descriptors from contained maps

+		// - We cannot guarantee here that these are really SubmodelDescriptors already and therefore need to default to maps

+		Collection<SubmodelDescriptor>  submodelDescriptors    = new LinkedList<>();

+		// - Fill sub model descriptors

+		for (Map<String, Object> currentMap: submodelDescriptorMaps) submodelDescriptors.add(new SubmodelDescriptor(currentMap)); 

+		

+		// Look for descriptor

+		for (SubmodelDescriptor desc: submodelDescriptors) {

+			System.out.println("Checking: "+desc.getId());		

+			

+			if (desc.getId().equals(subModelId)) return desc;

+		}

+		

+		// No Descritor found

+		return null;

+	}

+}

+

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/descriptor/SubmodelDescriptor.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/descriptor/SubmodelDescriptor.java
new file mode 100644
index 0000000..d4094ca
--- /dev/null
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/descriptor/SubmodelDescriptor.java
@@ -0,0 +1,92 @@
+package org.eclipse.basyx.aas.metamodel.hashmap.aas.descriptor;

+

+import java.util.Arrays;

+import java.util.HashMap;

+import java.util.LinkedList;

+import java.util.List;

+import java.util.Map;

+

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.SubModel;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.identifier.Identifier;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier.AdministrativeInformation;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier.Description;

+import org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier.haskind.Kind;

+

+

+

+

+/**

+ * AAS descriptor class

+ * 

+ * @author kuhn

+ *

+ */

+public class SubmodelDescriptor extends HashMap<String, Object> {

+

+		

+	/**

+	 * Version of serialized instances

+	 */

+	private static final long serialVersionUID = 1L;

+

+	

+	

+	/**

+	 * Create a new sub model descriptor with minimal information

+	 */

+	@SuppressWarnings("unchecked")

+	public SubmodelDescriptor(SubModel submodel, String endpoint, String endpointType) {

+		// Invoke default constructor

+		//this();

+		

+		put("idShort", submodel.getId());

+		

+		// Add identification and end point information

+		Identifier identifier = new Identifier();

+		identifier.setIdType(submodel.getIdentification().getIdType());

+		identifier.setId(submodel.getIdentification().getId());

+		put("identification", identifier);

+		

+		HashMap<String, String> endpointWrapper = new HashMap<String, String>(); 

+		endpointWrapper.put("type", endpointType);

+		endpointWrapper.put("address", endpoint);

+		

+		put("endpoints", Arrays.asList(endpointWrapper));

+	}

+	

+	/**

+	 * Create sub model descriptor from existing hash map

+	 */

+	public SubmodelDescriptor(Map<String, Object> map) {

+		// Put all elements from map into this descriptor

+		this.putAll(map);

+	}

+	

+	

+	/**

+	 * Return sub model ID

+	 */

+	@SuppressWarnings("unchecked")

+	public String getId() {

+		return new Identifier((Map<String, Object>) get("identification")).getId();

+	}

+	

+	

+	/**

+	 * Return sub model ID type

+	 */

+	@SuppressWarnings("unchecked")

+	public String getIdType() {

+		return new Identifier((Map<String, Object>) get("identification")).getIdType();

+	}

+

+	

+	/**

+	 * Return first sub model end point

+	 */

+	@SuppressWarnings("unchecked")

+	public String getFirstEndpoint() {

+		return ((List<String>) get("endpoints")).get(0);

+	}

+}

+

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/Description.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/Description.java
new file mode 100644
index 0000000..5930886
--- /dev/null
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/Description.java
@@ -0,0 +1,31 @@
+package org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier;

+

+import java.util.HashMap;

+

+

+

+/**

+ * AAS description class

+ * 

+ * @author kuhn

+ *

+ */

+public class Description extends HashMap<String, Object> {

+

+		

+	/**

+	 * Version of serialized instances

+	 */

+	private static final long serialVersionUID = 1L;

+

+	

+	

+	/**

+	 * Constructor

+	 */

+	public Description() {

+		// Add qualifiers

+		put("language", "");

+		put("text",     "");

+	}

+}

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/Referable.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/Referable.java
index 7a4e10c..a9fbe9a 100644
--- a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/Referable.java
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/Referable.java
@@ -1,6 +1,7 @@
 package org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier;

 

 import java.util.HashMap;

+import java.util.HashSet;

 

 import org.eclipse.basyx.aas.api.metamodel.aas.qualifier.IReferable;

 import org.eclipse.basyx.aas.api.metamodel.aas.reference.IReference;

@@ -39,7 +40,11 @@
 		// (String)

 		put(CATEGORY, "");

 		// Description or comments on the element (String)

-		put(DESCRIPTION, "");

+		

+		HashSet<HashMap<String, Object>> desc = new HashSet<HashMap<String, Object>>();

+		desc.add(new Description());

+			

+		put(DESCRIPTION, desc);

 		// Reference to the parent of this element (Referable)

 		put(PARENT, null);

 	}

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/qualifiable/Qualifiable.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/qualifiable/Qualifiable.java
index 6b08c54..1010bac 100644
--- a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/qualifiable/Qualifiable.java
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/qualifier/qualifiable/Qualifiable.java
@@ -1,69 +1,69 @@
-package org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier.qualifiable;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.eclipse.basyx.aas.api.metamodel.aas.qualifier.qualifiable.IConstraint;
-import org.eclipse.basyx.aas.api.metamodel.aas.qualifier.qualifiable.IQualifiable;
-import org.eclipse.basyx.aas.metamodel.facades.QualifiableFacade;
-
-/**
- * Qualifiable class
- * 
- * @author kuhn
- *
- */
-public class Qualifiable extends HashMap<String, Object> implements IQualifiable{
-
-	/**
-	 * Version of serialized instances
-	 */
-	private static final long serialVersionUID = 1L;
-	
-	public static final String QUALIFIER="qualifier";
-
-	/**
-	 * Constructor
-	 */
-	public Qualifiable() {
-		// The instance of an element may be further qualified by one or more
-		// qualifiers.
-		put(QUALIFIER, null);
-	}
-
-	/**
-	 * Constructor
-	 */
-	public Qualifiable(Constraint qualifier) {
-		// Create collection with qualifiers
-		Set<Constraint> qualifiers = new HashSet<Constraint>();
-		// - Add qualifier
-		qualifiers.add(qualifier);
-
-		// The instance of an element may be further qualified by one or more
-		// qualifiers.
-		put(QUALIFIER, qualifiers);
-	}
-
-	/**
-	 * Constructor
-	 */
-	public Qualifiable(Collection<Constraint> qualifier) {
-		// The instance of an element may be further qualified by one or more
-		// qualifiers.
-		put(QUALIFIER, qualifier);
-	}
-
-	@Override
-	public void setQualifier(Set<IConstraint> qualifiers) {
-		new QualifiableFacade(this).setQualifier(qualifiers);
-		
-	}
-
-	@Override
-	public Set<IConstraint> getQualifier() {
-		return new  QualifiableFacade(this).getQualifier();
-	}
-}
+package org.eclipse.basyx.aas.metamodel.hashmap.aas.qualifier.qualifiable;

+

+import java.util.Collection;

+import java.util.HashMap;

+import java.util.HashSet;

+import java.util.Set;

+

+import org.eclipse.basyx.aas.api.metamodel.aas.qualifier.qualifiable.IConstraint;

+import org.eclipse.basyx.aas.api.metamodel.aas.qualifier.qualifiable.IQualifiable;

+import org.eclipse.basyx.aas.metamodel.facades.QualifiableFacade;

+

+/**

+ * Qualifiable class

+ * 

+ * @author kuhn

+ *

+ */

+public class Qualifiable extends HashMap<String, Object> implements IQualifiable{

+

+	/**

+	 * Version of serialized instances

+	 */

+	private static final long serialVersionUID = 1L;

+	

+	public static final String QUALIFIER="constraints"; // changed qualifier to constraints xxxxx constantin

+

+	/**

+	 * Constructor

+	 */

+	public Qualifiable() {

+		// The instance of an element may be further qualified by one or more

+		// qualifiers.

+		put(QUALIFIER, null);

+	}

+

+	/**

+	 * Constructor

+	 */

+	public Qualifiable(Constraint qualifier) {

+		// Create collection with qualifiers

+		Set<Constraint> qualifiers = new HashSet<Constraint>();

+		// - Add qualifier

+		qualifiers.add(qualifier);

+

+		// The instance of an element may be further qualified by one or more

+		// qualifiers.

+		put(QUALIFIER, qualifiers);

+	}

+

+	/**

+	 * Constructor

+	 */

+	public Qualifiable(Collection<Constraint> qualifier) {

+		// The instance of an element may be further qualified by one or more

+		// qualifiers.

+		put(QUALIFIER, qualifier);

+	}

+

+	@Override

+	public void setQualifier(Set<IConstraint> qualifiers) {

+		new QualifiableFacade(this).setQualifier(qualifiers);

+		

+	}

+

+	@Override

+	public Set<IConstraint> getQualifier() {

+		return new  QualifiableFacade(this).getQualifier();

+	}

+}

diff --git a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/reference/Reference.java b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/reference/Reference.java
index 668056b..4f02c93 100644
--- a/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/reference/Reference.java
+++ b/sdks/java/basys.sdk/src/org/eclipse/basyx/aas/metamodel/hashmap/aas/reference/Reference.java
@@ -23,7 +23,7 @@
 public class Reference extends HashMap<String, Object> implements IReference {

 	private static final long serialVersionUID = 1L;

 	

-	public static final String KEY="key";

+	public static final String KEY="keys";

 

 	/**

 	 * Constructor