瀏覽代碼

Added code to execute model transformations

Yentl Van Tendeloo 8 年之前
父節點
當前提交
6b54788cf1
共有 4 個文件被更改,包括 161 次插入26 次删除
  1. 3 0
      bootstrap/object_operations.alc
  2. 151 24
      core/core_algorithm.alc
  3. 6 2
      core/core_formalism.mvc
  4. 1 0
      interface/HUTN/includes/object_operations.alh

+ 3 - 0
bootstrap/object_operations.alc

@@ -237,3 +237,6 @@ Element function allowedAssociationsBetween(model : Element, src : String, dst :
 			i = i + 1
 
 	return result!
+
+String function read_type(model : Element, name : String):
+	return reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][name]))!

+ 151 - 24
core/core_algorithm.alc

@@ -194,6 +194,36 @@ String function get_group_id(name : String):
 	
 	return ""!
 
+Void function model_create(model : Element, name : String, user_id : String, type_id : String):
+	String location
+
+	location = "/models/" + cast_id2s(model)
+	export_node(model, location)
+
+	// Manage meta-info
+	model_id = instantiate_node(core, "Model", "")
+	instantiate_attribute(core, model_id, "name", name)
+	instantiate_attribute(core, model_id, "location", location)
+	instantiate_attribute(core, model_id, "permissions", "200")
+	instantiate_link(core, "owner", "", model_id, user_id)
+	instantiate_link(core, "instanceOf", "", model_id, type_id)
+
+	return!
+
+Void function model_overwrite(model : Element, name : String):
+	String location
+	String model_id
+
+	location = "/models/" + cast_id2s(model)
+	export_node(model, location)
+	model_id = get_model_id(name)
+
+	// Change location in meta-data
+	unset_attribute(core, model_id, "location")
+	instantiate_attribute(core, model_id, "location", location)
+
+	return!
+
 Void function user_function_skip_init(user_id : String):
 	Boolean do_continue
 	String cmd
@@ -220,10 +250,6 @@ Void function user_function_skip_init(user_id : String):
 			output("    transformation_reRAMify			-- RAMify a merged metamodel again")
 			output("    transformation_add_MT			-- Initialize a new model transformation")
 			output("    transformation_add_AL			-- TODO")
-			output("    transformation_source_add		-- TODO")
-			output("    transformation_source_delete	-- TODO")
-			output("    transformation_target_add		-- TODO")
-			output("    transformation_target_delete	-- TODO")
 			output("    transformation_execute			-- TODO")
 			output("")
 			output("Model permission operations")
@@ -271,19 +297,8 @@ Void function user_function_skip_init(user_id : String):
 
 						// TODO Update construct_model call to this interface
 						new_model = construct_model(import_node(read_attribute(core, type_id, "location")))
-
+						model_create(new_model, name, user_id, type_id)
 						output("Model upload success!")
-						location = "/models/" + cast_id2s(new_model)
-						export_node(new_model, location)
-
-						// Manage meta-info
-						new_model_id = instantiate_node(core, "Model", "")
-						instantiate_attribute(core, new_model_id, "name", name)
-						instantiate_attribute(core, new_model_id, "location", location)
-						instantiate_attribute(core, new_model_id, "permissions", "200")
-						instantiate_link(core, "owner", "", new_model_id, user_id)
-						instantiate_link(core, "instanceOf", "", new_model_id, type_id)
-						output("Meta-info correctly set!")
 					else:
 						output("Model with that name already exists!")
 				else:
@@ -291,6 +306,124 @@ Void function user_function_skip_init(user_id : String):
 			else:
 				output("Could not find type model!")
 
+		elif (cmd == "transformation_execute"):
+			// Execute a transformation, whatever type it is
+			// First we detect the type, so we know how to prepare for invocation
+			String transformation_id
+			String exact_type
+			Element sources
+			Element targets
+			String source
+			String target
+			String name_id
+
+			output("Which transformation do you want to execute?")
+			transformation_id = get_model_id(input())
+			if (transformation_id != ""):
+				if (allow_read(user_id, transformation_id)):
+					if (is_nominal_instance(core, transformation_id, "Transformation")):
+						// Read out source and target links
+						sources = readOutgoingAssociationInstances(core, transformation_id, "transformInput")
+						inputs = create_node()
+						while (read_nr_out(source) > 0):
+							source = set_pop(sources)
+							output(string_join("Which model to bind for source element ", read_attribute(core, source, "name")))
+							name_id = get_model_id(input())
+							if (name_id != ""):
+								if (allow_read(user_id, name_id)):
+									dict_add(inputs, read_attribute(core, source, "name"), name_id)
+								else:
+									output("Permission denied")
+									set_add(sources, source)
+							else:
+								output("No such model")
+								set_add(sources, source)
+
+						targets = readOutgoingAssociationInstances(core, transformation_id, "transformOutput")
+						outputs = create_node()
+						while (read_nr_out(targets) > 0):
+							target = set_pop(targets)
+							output(string_join("Which model to create for target element ", read_attribute(core, target, "name")))
+							name_id = get_model_id(input())
+							dict_add(outputs, read_attribute(core, target, "name"), name_id)
+
+						exact_type = read_type(core, transformation_id)
+						if (exact_type == "ModelTransformation"):
+							// Model transformation is always in-place and uses only a single metamodel
+							// Therefore, we must:
+							//		1) Create an empty model, instance of merged metamodel
+							// 		2) Merge the different source models and retype
+							//		3) Perform the transformation on the merged model
+							//		4) Split the resulting model based on the target formalisms
+							//
+							// There is one exception: if the target model is bound to a source model, that model is overwritten
+							// This allows for some optimizations when it is a simple in-place transformation (skip model copy, join, and split)
+							// First check for this exception, as it is much faster
+							Element input_model
+							Element schedule_model
+
+							schedule_model = import_node(read_attribute(core, transformation_id, "location"))
+							if (bool_and(bool_and(read_nr_out(inputs) == 1, read_nr_out(outputs) == 1), set_equality(inputs, outputs))):
+								// inputs and outputs have the same values and there is only one: keep in-place without additional bookkeeping
+								input_model = import_node(read_attribute(core, set_pop(inputs), "location"))
+								transform(input_model, schedule_model)
+							else:
+								// Need to fall back to the default approach, which is way slower
+								// 1) Create empty instance of merged metamodel
+
+								trace_links = allOutgoingAssociationInstances(core, transformation_id, "tracability")
+								ramified_metamodel = ""
+								while (read_nr_out(trace_links) > 0):
+									trace_link_id = set_pop(trace_links)
+									if (read_attribute(core, trace_link_id, "type") == "ramified"):
+										ramified_metamodel = readAssociationDestination(core, trace_link_id)
+								if (ramified_metamodel != ""):
+									merged_model = instantiate_model(import_node(merged_metamodel))
+
+									// 2) Merge source models
+
+									String key
+									Element keys
+									input_keys = dict_keys(inputs)
+									while (read_nr_out(input_keys) > 0):
+										key = set_pop(input_keys)
+										model = import_node(read_attribute(core, inputs[key], "location"))
+										model_join(merged_model, model, key)
+
+									// 3) Transform
+
+									transform(merged_model, schedule_model)
+
+									// 4) Split in different files depending on type
+
+									output_keys = dict_keys(outputs)
+									while (read_nr_out(output_keys) > 0):
+										key = set_pop(output_keys)
+										desired_metamodel_id = followAssociation(core, outputs[key])
+										desired_metamodel = import_node(read_attribute(core, desired_metamodel_id, "location"))
+										split_off_model = model_split(merged_model, desired_metamodel, key)
+
+										// Check if the destination model already exists
+										if (get_model_id(outputs[key]) == ""):
+											// New model
+											model_create(split_off_model, outputs[key], user_id, desired_metamodel_id)
+										else:
+											// Model exists, so we overwrite
+											model_overwrite(split_off_model, outputs[key])
+
+								else:
+									output("Could not resolve intermediate merged metamodel")
+						elif (exact_type == "ActionLanguage"):
+							output("Not Implemented yet!)
+						else:
+							output("Did not know how to interpret model of type " + exact_type)
+					else:
+						output("Model is not an executable transformation")
+				else:
+					output("Permission denied")
+			else:
+				output("No such transformation")
+
 		elif (cmd == "model_overwrite"):
 			// Overwrites an existing model without changing any metadata
 
@@ -301,14 +434,8 @@ Void function user_function_skip_init(user_id : String):
 					if (allow_read(user_id, followAssociation(core, model_id, "instanceOf"))):
 						output("Waiting for model constructors...")
 						new_model = construct_model(import_node(read_attribute(core, followAssociation(core, model_id, "instanceOf"), "location")))
-						output("Model upload success!")
-						location = "/models/" + cast_id2s(new_model)
-						export_node(new_model, location)
-
-						// Change location in meta-data
-						unset_attribute(core, model_id, "location")
-						instantiate_attribute(core, model_id, "location", location)
-						output("Model completely overwritten")
+						model_overwrite(new_model, model_id)
+						output("Model overwrite success!")
 					else:
 						output("Permission denied")
 				else:

+ 6 - 2
core/core_formalism.mvc

@@ -77,8 +77,12 @@ SimpleClassDiagrams CoreFormalism {
 
     Class ActionLanguage : Transformation {}
 
-    Association transformInput (Model, Transformation) {}
-    Association transformOutput (Transformation, Model) {}
+    Association transformInput (Model, Transformation) {
+        name : String
+    }
+    Association transformOutput (Transformation, Model) {
+        name : String
+    }
 
     Association tracability (Model, Model) {
         type : String

+ 1 - 0
interface/HUTN/includes/object_operations.alh

@@ -12,3 +12,4 @@ String function readAssociationDestination(model : Element, name : String)
 String function followAssociation(model : Element, element_name : String, association_name : String)
 Element function allAssociationDestinations(model : Element, name : String, association_type : String)
 Element function allowedAssociationsBetween(model : Element, src : String, dst : String)
+String function read_type(model : Element, name : String)