CORD-2753 Allow owner_class_name to be set for ServiceInstances

Change-Id: Ia67882027a3c18bfada099bcf83cd016558c47cf
diff --git a/lib/xos-genx/xosgenx/targets/service.xtarget b/lib/xos-genx/xosgenx/targets/service.xtarget
index 9d2915d..a9ca934 100644
--- a/lib/xos-genx/xosgenx/targets/service.xtarget
+++ b/lib/xos-genx/xosgenx/targets/service.xtarget
@@ -43,6 +43,10 @@
 
   KIND = {{ xproto_first_non_empty([m.options.kind, options.kind, options.name, "Set a kind in your xproto!"]) }}
 
+  {% if m.options.owner_class_name %}
+  OWNER_CLASS_NAME = {{ m.options.owner_class_name }}
+  {% endif %}
+
   class Meta:
       app_label = {{ xproto_first_non_empty([m.options.app_label, options.app_label, options.name, "Set an app label in your xproto!"]) | lower}}
       # name = {{ xproto_first_non_empty([m.options.name, options.name, "Set a name in your xproto!"]) }}
diff --git a/xos/core/models/serviceinstance.py b/xos/core/models/serviceinstance.py
index 9cc6dab..a4ab59d 100644
--- a/xos/core/models/serviceinstance.py
+++ b/xos/core/models/serviceinstance.py
@@ -63,3 +63,33 @@
             return None
         return sorted(st, key=attrgetter('id'))[0]
 
+    def save(self, *args, **kwargs):
+        if hasattr(self, "OWNER_CLASS_NAME"):
+            owner_class = self.get_model_class_by_name(self.OWNER_CLASS_NAME)
+            if not owner_class:
+                raise XOSValidationError("Cannot find owner class %s" % self.OWNER_CLASS_NAME)
+
+            need_set_owner = True
+            if self.owner_id:
+                # Check to see if owner is set to a valid instance of owner_class. If it is, then we already have an
+                # owner. If it is not, then some other misbehaving class must have altered the ServiceInstance.meta
+                # to point to its own default (these services are being cleaned up).
+                if owner_class.objects.filter(id=self.owner_id).exists():
+                    need_set_owner = False
+
+            if need_set_owner:
+                owners = owner_class.objects.all()
+                if not owners:
+                    raise XOSValidationError("Cannot find eligible owner of class %s" % self.OWNER_CLASS_NAME)
+
+                self.owner = owners[0]
+
+        # If the model has a Creator and it's not specified, then attempt to default to the Caller. Caller is
+        # automatically filled in my the API layer. This code was typically used by ServiceInstances that lead to
+        # instance creation.
+        if (hasattr(self, "creator")) and (not self.creator) and (hasattr(self, "caller")) and (self.caller):
+            self.creator = self.caller
+
+        super(ServiceInstance, self).save(*args, **kwargs)
+
+
diff --git a/xos/core/models/xosbase_header.py b/xos/core/models/xosbase_header.py
index f16b611..ae42c3e 100644
--- a/xos/core/models/xosbase_header.py
+++ b/xos/core/models/xosbase_header.py
@@ -144,6 +144,15 @@
     def get_field_diff(self, field_name):
         return self.diff.get(field_name, None)
 
+    @classmethod
+    def get_model_class_by_name(cls, name):
+        all_models = django.apps.apps.get_models(include_auto_created=False)
+        all_models_by_name = {}
+        for model in all_models:
+            all_models_by_name[model.__name__] = model
+
+        return all_models_by_name.get(name)
+
     @property
     def leaf_model(self):
         leaf_model_name = getattr(self, "leaf_model_name", None)
@@ -153,12 +162,7 @@
         if (leaf_model_name == self.__class__.__name__):
             return self
 
-        all_models = django.apps.apps.get_models(include_auto_created=False)
-        all_models_by_name = {}
-        for model in all_models:
-            all_models_by_name[model.__name__] = model
-
-        leaf_model_class = all_models_by_name.get(self.leaf_model_name)
+        leaf_model_class = self.get_model_class_by_name(self.leaf_model_name)
 
         assert (self.id)