move get_attribute/set_attribute to a mixin
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index b90d765..cb33c2f 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -5,7 +5,31 @@
 from operator import attrgetter
 import json
 
-class Service(PlCoreBase):
+class AttributeMixin(object):
+    # helper for extracting things from a json-encoded service_specific_attribute
+    def get_attribute(self, name, default=None):
+        if self.service_specific_attribute:
+            attributes = json.loads(self.service_specific_attribute)
+        else:
+            attributes = {}
+        return attributes.get(name, default)
+
+    def set_attribute(self, name, value):
+        if self.service_specific_attribute:
+            attributes = json.loads(self.service_specific_attribute)
+        else:
+            attributes = {}
+        attributes[name]=value
+        self.service_specific_attribute = json.dumps(attributes)
+
+    def get_initial_attribute(self, name, default=None):
+        if self._initial["service_specific_attribute"]:
+            attributes = json.loads(self._initial["service_specific_attribute"])
+        else:
+            attributes = {}
+        return attributes.get(name, default)
+
+class Service(PlCoreBase, AttributeMixin):
     # when subclassing a service, redefine KIND to describe the new service
     KIND = "generic"
 
@@ -154,7 +178,7 @@
             qs = SitePrivilege.objects.filter(user=user)
         return qs
 
-class TenantRoot(PlCoreBase):
+class TenantRoot(PlCoreBase, AttributeMixin):
     """ A tenantRoot is one of the things that can sit at the root of a chain
         of tenancy. This object represents a node.
     """
@@ -171,23 +195,6 @@
         self._meta.get_field("kind").default = self.KIND
         super(TenantRoot, self).__init__(*args, **kwargs)
 
-
-    # helper for extracting things from a json-encoded attribute
-    def get_attribute(self, name, default=None):
-        if self.service_specific_attribute:
-            attributes = json.loads(self.service_specific_attribute)
-        else:
-            attributes = {}
-        return attributes.get(name, default)
-
-    def set_attribute(self, name, value):
-        if self.service_specific_attribute:
-            attributes = json.loads(self.service_specific_attribute)
-        else:
-            attributes = {}
-        attributes[name]=value
-        self.service_specific_attribute = json.dumps(attributes)
-
     def __unicode__(self):
         if not self.name:
             return u"%s-tenant_root-#%s" % (str(self.kind), str(self.id))
@@ -211,7 +218,7 @@
     def get_tenant_objects(cls):
         return cls.objects.filter(kind = cls.KIND)
 
-class Tenant(PlCoreBase):
+class Tenant(PlCoreBase, AttributeMixin):
     """ A tenant is a relationship between two entities, a subscriber and a
         provider. This object represents an edge.
 
@@ -252,29 +259,6 @@
     def __unicode__(self):
         return u"%s-tenant-%s" % (str(self.kind), str(self.id))
 
-    # helper for extracting things from a json-encoded service_specific_attribute
-    def get_attribute(self, name, default=None):
-        if self.service_specific_attribute:
-            attributes = json.loads(self.service_specific_attribute)
-        else:
-            attributes = {}
-        return attributes.get(name, default)
-
-    def set_attribute(self, name, value):
-        if self.service_specific_attribute:
-            attributes = json.loads(self.service_specific_attribute)
-        else:
-            attributes = {}
-        attributes[name]=value
-        self.service_specific_attribute = json.dumps(attributes)
-
-    def get_initial_attribute(self, name, default=None):
-        if self._initial["service_specific_attribute"]:
-            attributes = json.loads(self._initial["service_specific_attribute"])
-        else:
-            attributes = {}
-        return attributes.get(name, default)
-
     @classmethod
     def get_tenant_objects(cls):
         return cls.objects.filter(kind = cls.KIND)