Example #1
0
    def __init__(self):

        self.manager_r = ResourceManager()
        self.manager_l = LinkManager()
        self.jungler_p = PathManager()
        self.rd_baker = ResourceDataBaker()
        self.PostMan = PostMan()
    def __init__(self):

        self.manager_r = ResourceManager()
        self.manager_l = LinkManager()
        self.jungler_p = PathManager()
        self.rd_baker = ResourceDataBaker()
        self.PostMan = PostMan()
    def __init__(self, req, location=None, idontknow=None, idontcare=None):

        self.req = req

        self.location = location

        self.idontcare = idontcare
        self.idontknow = idontknow

        self.triggered_action = None
        self.path_url = self.req.path_url

        self.res = Response()
        self.res.content_type = str(req.accept)
        self.res.server = 'ocni-server/1.1 (linux) OCNI/1.1'

        self.req_adapter = RequestAdapter()
        self.res_adapter = ResponseAdapter()
        self.jungler = MultiEntityJungler()
        self.jungler_p = PathManager()
    def __init__(self, req, location=None, idontknow=None, idontcare=None):
        self.req = req

        self.location = location

        self.idontcare = idontcare
        self.idontknow = idontknow

        self.triggered_action = None
        self.path_url = self.req.path_url

        self.res = Response()
        self.res.content_type = str(req.accept)
        self.res.server = 'ocni-server/1.1 (linux) OCNI/1.1'

        self.req_adapter = RequestAdapter()
        self.res_adapter = ResponseAdapter()
        self.jungler = MultiEntityJungler()
        self.jungler_p = PathManager()
class MultiEntityDispatcher(object):
    """
    Dispatches requests concerning multiple entities

    """
    def __init__(self, req, location=None, idontknow=None, idontcare=None):

        self.req = req

        self.location = location

        self.idontcare = idontcare
        self.idontknow = idontknow

        self.triggered_action = None
        self.path_url = self.req.path_url

        self.res = Response()
        self.res.content_type = str(req.accept)
        self.res.server = 'ocni-server/1.1 (linux) OCNI/1.1'

        self.req_adapter = RequestAdapter()
        self.res_adapter = ResponseAdapter()
        self.jungler = MultiEntityJungler()
        self.jungler_p = PathManager()

    def post(self):
        """
        Create a new entity or trigger an action on all resources belonging to a kind or attach a mixin to a
        resource instance

        """

        #Step[1]: Detect the data type (HTTP ,OCCI:JSON or OCCI+JSON)

        jBody = self.req_adapter.convert_request_entity_content(self.req)

        if jBody is None:
            self.res.status_int = return_code['Not Acceptable']
            self.res.body = self.req.content_type + " is an unknown request content type"

        else:
            #Step[2]: Identify the action name if there is one:

            if self.req.params.has_key('action'):
                self.triggered_action = self.req.params['action']

            #Step[3a]: Dispatch a post request

            if self.triggered_action is None:

                var, self.res.status_int = self.jungler.channel_post_multi_resources(
                    jBody, self.path_url)

                #Step[4a]: Adapt response to the required Accept-Type

                if self.res.status_int == return_code[
                        'OK, and location returned']:
                    self.res_adapter.convert_response_entity_multi_location_content(
                        var, self.res)

                else:
                    self.res.content_type = "text/html"
                    self.res.body = str(var)

            #Step[3b]: Trigger an action on all resources belonging to a kind
            else:
                self.res.body, self.res.status_int = self.jungler.channel_trigger_actions(
                    jBody, self.path_url, self.triggered_action)

            return self.res

    def get(self):
        """
        Get entities belonging to a kind or a mixin

        """

        #Step[1]: Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)

        if self.req.content_type == 'text/occi' or (self.req.body != ""):

            jBody = self.req_adapter.convert_request_entity_content_v2(
                self.req)

            if jBody is None:
                self.res.status_int = return_code['Not Acceptable']
                self.res.body = self.req.content_type + " is an unknown request content type"

            else:
                #Step[2a]: Retrieve entities matching the filter provided
                var, self.res.status_int = self.jungler.channel_get_filtered_entities(
                    self.path_url, jBody)

        else:
            #Step[2b]: Retrieve all the entities
            var, self.res.status_int = self.jungler.channel_get_all_entities(
                self.path_url, "")

        #Step[3]: Adapt the response to the format defined in the Accept-Type header

        if self.res.status_int == return_code['OK']:

            self.res_adapter.convert_response_entity_multi_x_occi_location_content(
                var, self.res)

        else:
            self.res.content_type = "text/html"
            self.res.body = str(var)

        return self.res

    def put(self):
        """
        Fully update the mixin collection of entities

        """

        #Step[1]: Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)

        jBody = self.req_adapter.convert_request_category_content(self.req)

        if jBody is None:
            self.res.status_int = return_code['Not Acceptable']
            self.res.body = self.req.content_type + " is an unknown request content type"
        else:

            #Step[2]: Fully update the mixin collection of entities

            self.res.body, self.res.status_int = self.jungler.channel_put_multi(
                jBody, self.path_url)

        return self.res

    def delete(self):
        """
        Dissociates a resource instance from a mixin or delete all resource under a path

        """

        #Step[1]: Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)
        if self.req.content_type == 'text/occi' or (self.req.body != ""):

            jBody = self.req_adapter.convert_request_category_content(self.req)

            if jBody is None:
                self.res.status_int = return_code['Not Acceptable']
                self.res.body = self.req.content_type + " is an unknown request content type"

                #Step[2a]: This is a dissociate mixin request
                self.res.body, self.res.status_int = self.jungler.channel_delete_multi(
                    jBody, self.path_url)
        else:
            #Step[2b]: This is a delete on path request:
            self.jungler_p.channel_delete_on_path(self.path_url)

        return self.res
class MultiEntityDispatcher(object):
    """


    """

    def __init__(self, req, location=None, idontknow=None, idontcare=None):
        self.req = req

        self.location = location

        self.idontcare = idontcare
        self.idontknow = idontknow

        self.triggered_action = None
        self.path_url = self.req.path_url

        self.res = Response()
        self.res.content_type = str(req.accept)
        self.res.server = 'ocni-server/1.1 (linux) OCNI/1.1'

        self.req_adapter = RequestAdapter()
        self.res_adapter = ResponseAdapter()
        self.jungler = MultiEntityJungler()
        self.jungler_p = PathManager()


    def post(self):
        """
        Create a new entity instance or trigger an action on all resources belonging to a kind or attach a mixin to a
        resource instance

        """

        #Step[1]: Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)


        jBody = self.req_adapter.convert_request_entity_content(self.req)

        if jBody is None:
            self.res.status_code = return_code['Not Acceptable']
            self.res.body = self.req.content_type + " is an unknown request content type"

        else:
            #Step[2]: Treat the data and define what the request really wants:

            if self.req.params.has_key('action'):
                self.triggered_action = self.req.params['action']

            #add the JSON to database along with other attributes
            if self.triggered_action is None:
                var, self.res.status_code = self.jungler.channel_post_multi_resources(jBody, self.path_url)

                if self.res.status_code == return_code['OK, and location returned']:
                    self.res_adapter.convert_response_entity_multi_location_content(var, self.res)

                else:
                    self.res.content_type = "text/html"
                    self.res.body = str(var)

            else:
                self.res.body, self.res.status_code = self.jungler.channel_trigger_actions(jBody, self.path_url,
                    self.triggered_action)

            return self.res

    def get(self):
        """
        Gets entities belonging to a kind or a mixin

        """

        #Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)

        if  self.req.content_type == 'text/occi' or (
        self.req.body != ""):
            jBody = self.req_adapter.convert_request_entity_content_v2(self.req)

            if jBody is None:
                self.res.status_code = return_code['Not Acceptable']
                self.res.body = self.req.content_type + " is an unknown request content type"

            else:
                var, self.res.status_code = self.jungler.channel_get_filtered_entities(self.path_url, jBody)

        else:
            var, self.res.status_code = self.jungler.channel_get_all_entities(self.path_url, "")

        if self.res.status_code == return_code['OK']:
            self.res_adapter.convert_response_entity_multi_x_occi_location_content(var, self.res)

        else:
            self.res.content_type = "text/html"
            self.res.body = str(var)

        return self.res

    def put(self):
        """
        Update the mixin collection of entities

        """

        #Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)
        #Not implemented yet for text/plain and text/occi formats


        jBody = self.req_adapter.convert_request_category_content(self.req)

        if jBody is None:
            self.res.status_code = return_code['Not Acceptable']
            self.res.body = self.req.content_type + " is an unknown request content type"
        else:
            #add the JSON to database along with other attributes
            self.res.body, self.res.status_code = self.jungler.channel_put_multi(jBody, self.path_url)

        return self.res

    def delete(self):
        """
        Dissociates a resource instance from a mixin

        """

        #Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)
        #Not implemented yet for text/plain and text/occi formats

        jBody = self.req_adapter.convert_request_category_content(self.req)

        if jBody is None:
            self.res.status_code = return_code['Not Acceptable']
            self.res.body = self.req.content_type + " is an unknown request content type"
        else:
            if self.req.body is not "":
                #This is a dissociate mixin request:
                self.res.body, self.res.status_code = self.jungler.channel_delete_multi(jBody, self.path_url)
            else:
                #This is a delete on path request:
                self.jungler_p.channel_delete_on_path(self.path_url)

        return self.res
class MultiEntityJungler(object):
    """
    Handles requests concerning multiple entities

    """

    def __init__(self):

        self.manager_r = ResourceManager()
        self.manager_l = LinkManager()
        self.jungler_p = PathManager()
        self.rd_baker = ResourceDataBaker()
        self.PostMan = PostMan()

    def channel_post_multi_resources(self, jreq, req_path):
        """
        Identifies the post path's goal : create a resource instance or update a mixin collection
        Args:
            @param jreq: Body content of the post request
            @param req_path: Address to which this post request was sent
        """
        # Step[1]: detect the goal of the request

        if jreq.has_key("resources") or jreq.has_key("links"):
            is_kind_loc = True
        else:
            is_kind_loc = False

        if is_kind_loc is True:

            # Step[2a]: This is a create new resources request

            db_occi_ids_locs = self.rd_baker.bake_to_post_multi_resources_2a()

            # Step[3a]: Look for the default attributes to complete the attribute description of the resource:
            default_attributes = self.rd_baker.bake_to_get_default_attributes(req_path)

            if db_occi_ids_locs is None or default_attributes is None:
                return "An error has occurred, please check log for more details", return_code["Internal Server Error"]
            else:

                # Step[4a]: Ask the managers to create the new resources

                if jreq.has_key("resources"):
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on kind path to create a new resource channeled"
                    )
                    new_resources, resp_code_r = self.manager_r.register_resources(
                        jreq["resources"], req_path, db_occi_ids_locs, default_attributes
                    )
                else:
                    new_resources = list()
                    resp_code_r = return_code["OK, and location returned"]

                if jreq.has_key("links"):
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on kind path to create a new link channeled"
                    )
                    new_links, resp_code_l = self.manager_l.register_links_explicit(
                        jreq["links"], req_path, db_occi_ids_locs, default_attributes
                    )
                else:
                    new_links = list()
                    resp_code_l = return_code["OK, and location returned"]

                if (
                    resp_code_r is not return_code["OK, and location returned"]
                    or resp_code_l is not return_code["OK, and location returned"]
                ):
                    return "An error has occurred, please check log for more details", return_code["Bad Request"]

                # Step[5a]: Save the new resources
                entities = new_resources + new_links

                self.PostMan.save_registered_docs_in_db(entities)
                logger.debug("===== Channel_post_multi_resources ==== : Finished (2a) with success")

                locations = list()

                for item in entities:
                    locations.append(item["OCCI_Location"])

                backend_m.create_entities(entities)

                return locations, return_code["OK, and location returned"]

                # Step[2b]: This is an associate mixins to resources request

        elif jreq.has_key("X-OCCI-Location"):

            # Step[3b]: Get the necessary data from DB
            nb_res, mix_id = self.rd_baker.bake_to_post_multi_resources_2b(req_path)

            if nb_res is None:
                return "An error has occurred, please check log for more details", return_code["Internal Server Error"]
            elif nb_res is 0:
                return "An error has occurred, please check log for more details", return_code["Not Found"]
            else:
                to_search_for = jreq["X-OCCI-Location"]

                db_docs = self.rd_baker.bake_to_post_multi_resources_2b2(to_search_for)

                if db_docs is 0:
                    return "An error has occurred, please check log for more details", return_code["Not Found"]

                elif db_docs is None:
                    return (
                        "An error has occurred, please check log for more details",
                        return_code["Internal Server Error"],
                    )

                else:
                    # Step[4b]: Ask the managers to associate mixins to resources
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on mixin path to associate a mixin channeled"
                    )
                    updated_entities, resp_code_e = associate_entities_to_a_mixin(mix_id, db_docs)

                    self.PostMan.save_updated_docs_in_db(updated_entities)
                    logger.debug("===== Channel_post_multi_resources ==== : Finished (2b) with success")
                    backend_m.update_entities(db_docs, updated_entities)
                    return "", return_code["OK"]
        else:
            return "An error has occurred, please check log for more details", return_code["Bad Request"]

    def channel_get_all_entities(self, req_path, jreq):
        """
        Retrieve all entities belonging to a kind or a mixin or get on a path

        Args:
            @param req_path: Address to which this post request was sent
            @param jreq: Data provided for filtering
        """

        # Step[1]: Retrieve the kind/mixin from DB

        res = self.rd_baker.bake_to_channel_get_all_entities(req_path)

        if res is None:
            return "An error has occurred, please check log for more details", return_code["Internal Server Error"]

        elif res is 0:

            logger.warning("===== Channel_get_all_multi_entities ===== : This is a get on a path " + req_path)
            # Step[1b]: Get on path to retrieve the entities under that path
            var, resp_code = self.jungler_p.channel_get_on_path(req_path, jreq)
            return var, resp_code

        else:
            q = res.first()
            # Step[2]: Retrieve the entities related to the kind/mixin
            entities = self.rd_baker.bake_to_get_all_entities(q["value"][1], q["value"][0])
            if entities is None:
                return "An error has occurred, please check log for more details", return_code["Internal Server Error"]

            else:

                logger.debug("===== Channel_get_all_entities ==== : Finished with success")
                return entities, return_code["OK"]

    def channel_get_filtered_entities(self, req_path, terms):
        """
        Retrieve entities belonging to a kind or a mixin matching the terms specified or get entities on a path with filtering
        Args:
            @param req_path: Address to which this post request was sent
            @param terms: Terms to filter entities
        """
        # Step[1]: Get all the entities related to kind/mixin or get on a path with filtering
        entities, ok = self.channel_get_all_entities(req_path, terms)

        if ok == return_code["OK"]:
            # Note: We now need the resources OCCI descriptions so we go back to the database
            descriptions_res, descriptions_link = self.rd_baker.bake_to_get_filtered_entities(entities)

            if descriptions_res is None:
                return "An error has occurred, please check log for more details", return_code["Internal Server Error"]
            else:
                # Step[2]: Ask the managers to do the filtering
                if terms.has_key("resources"):
                    logger.debug("===== Channel_get_filtered: Resources are sent to filter =====")
                    filtered_res, resp_code_r = self.manager_r.get_filtered_resources(
                        terms["resources"], descriptions_res
                    )
                else:
                    logger.debug("===== Channel_get_filtered: No Resource filter =====")
                    filtered_res = list()
                    resp_code_r = return_code["OK"]

                if terms.has_key("links"):
                    logger.debug("===== Channel_get_filtered: Links are sent to filter =====")
                    filtered_links, resp_code_l = self.manager_l.get_filtered_links(terms["links"], descriptions_link)
                else:
                    logger.debug("===== Channel_get_filtered: No Links filter =====")
                    filtered_links = list()
                    resp_code_l = return_code["OK"]

                if resp_code_l is not return_code["OK"] or resp_code_r is not return_code["OK"]:
                    return "An error has occurred, please check log for more details", return_code["Bad Request"]

                result = filtered_res + filtered_links

                logger.debug("===== Channel_get_filtered_entities ==== : Finished with success")

                return result, return_code["OK"]

    def channel_put_multi(self, jreq, req_url):
        """
        Update the mixin collection of resources
        Args:

            @param jreq: OCCI_Locations of the resources
            @param req_url: URL of the request
        """

        # Step[1]: Get the necessary data from DB

        nb_res, mix_id = self.rd_baker.bake_to_post_multi_resources_2b(req_url)
        if nb_res is None:
            return "An error has occurred, please check log for more details", return_code["Internal Server Error"]
        elif nb_res is 0:
            return "An error has occurred, please check log for more details", return_code["Not Found"]
        else:
            to_search_for = jreq["X-OCCI-Location"]
            db_docs = self.rd_baker.bake_to_post_multi_resources_2b2(to_search_for)

            if db_docs is 0:
                return "An error has occurred, please check log for more details", return_code["Not Found"]

            elif db_docs is None:
                return "An error has occurred, please check log for more details", return_code["Internal Server Error"]

            else:
                # Step[2]: Ask the managers to associate mixins to resources
                logger.debug(
                    "===== Channel_put_multi_resources ==== : Put on mixin path to associate a mixin channeled"
                )
                updated_entities, resp_code_e = associate_entities_to_a_mixin(mix_id, db_docs)

                self.PostMan.save_updated_docs_in_db(updated_entities)

                logger.debug("===== Channel_put_multi_resources ==== : Finished (2b) with success")
                backend_m.update_entities(db_docs, updated_entities)
                return "", return_code["OK"]

    def channel_delete_multi(self, jreq, req_url):
        """
        Remove the mixin from the resources
        Args:
            @param jreq: OCCI_Locations of the resources
            @param req_url: URL of the request
        """

        # Step[1]: Get the necessary data from DB

        nb_res, mix_id = self.rd_baker.bake_to_post_multi_resources_2b(req_url)
        if nb_res is None:
            return "An error has occurred, please check log for more details", return_code["Internal Server Error"]

        elif nb_res is 0:
            return "An error has occurred, please check log for more details", return_code["Not Found"]

        else:
            to_search_for = jreq["X-OCCI-Location"]
            db_docs = self.rd_baker.bake_to_post_multi_resources_2b2(to_search_for)

            if db_docs is 0:
                return "An error has occurred, please check log for more details", return_code["Not Found"]

            elif db_docs is None:
                return "An error has occurred, please check log for more details", return_code["Internal Server Error"]

            else:
                logger.debug(" ===== Delete_multi_entities : Delete on mixin to Dissociate mixins channeled =====")
                updated_entities, resp_code_e = dissociate_entities_from_a_mixin(mix_id, db_docs)

            if resp_code_e is not return_code["OK"]:
                return "An error has occurred, please check log for more details", return_code["Bad Request"]

            self.PostMan.save_updated_docs_in_db(updated_entities)

            backend_m.update_entities(db_docs, updated_entities)

            return "", return_code["OK"]

    def channel_trigger_actions(self, jBody, req_url, triggered_action):
        """
        Trigger action on a collection of resources related to a kind or mixin
        Args:
            @param jBody: Action provided
            @param req_url: URL of the request
            @param triggered_action: Action name
        """

        # Step[1]: Get the necessary data:

        kind_ids, entities = self.rd_baker.bake_to_channel_trigger_actions(req_url)

        if kind_ids is None:
            return "An error has occurred, please check log for more details", return_code["Internal Server Error"]
        if kind_ids is 0:
            return "An error has occured, please check log for more details", return_code["Not Found"]
        else:
            providers = list()
            # Step[2]: Get the providers of the instances
            for item in kind_ids:
                provider = self.rd_baker.bake_to_get_provider(item)
                providers.append(provider)

            if jBody.has_key("attributes") is True:

                parameters = jBody["attributes"]
            else:
                parameters = None

            # Step[3]: Ask the backend to trigger the action on the resources
            backend_m.trigger_action_on_multi_resource(entities, providers, jBody["actions"][0], parameters)

            return "", return_code["OK"]
class MultiEntityDispatcher(object):
    """
    Dispatches requests concerning multiple entities

    """

    def __init__(self, req, location=None, idontknow=None, idontcare=None):

        self.req = req

        self.location = location

        self.idontcare = idontcare
        self.idontknow = idontknow

        self.triggered_action = None
        self.path_url = self.req.path_url

        self.res = Response()
        self.res.content_type = str(req.accept)
        self.res.server = 'ocni-server/1.1 (linux) OCNI/1.1'

        self.req_adapter = RequestAdapter()
        self.res_adapter = ResponseAdapter()
        self.jungler = MultiEntityJungler()
        self.jungler_p = PathManager()


    def post(self):
        """
        Create a new entity or trigger an action on all resources belonging to a kind or attach a mixin to a
        resource instance

        """

        #Step[1]: Detect the data type (HTTP ,OCCI:JSON or OCCI+JSON)


        jBody = self.req_adapter.convert_request_entity_content(self.req)

        if jBody is None:
            self.res.status_int = return_code['Not Acceptable']
            self.res.body = self.req.content_type + " is an unknown request content type"

        else:
            #Step[2]: Identify the action name if there is one:

            if self.req.params.has_key('action'):
                self.triggered_action = self.req.params['action']

            #Step[3a]: Dispatch a post request

            if self.triggered_action is None:

                var, self.res.status_int = self.jungler.channel_post_multi_resources(jBody, self.path_url)

                #Step[4a]: Adapt response to the required Accept-Type

                if self.res.status_int == return_code['OK, and location returned']:
                    self.res_adapter.convert_response_entity_multi_location_content(var, self.res)

                else:
                    self.res.content_type = "text/html"
                    self.res.body = str(var)

            #Step[3b]: Trigger an action on all resources belonging to a kind
            else:
                self.res.body, self.res.status_int = self.jungler.channel_trigger_actions(jBody, self.path_url,
                    self.triggered_action)

            return self.res

    def get(self):
        """
        Get entities belonging to a kind or a mixin

        """

        #Step[1]: Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)

        if  self.req.content_type == 'text/occi' or (
        self.req.body != ""):

            jBody = self.req_adapter.convert_request_entity_content_v2(self.req)

            if jBody is None:
                self.res.status_int = return_code['Not Acceptable']
                self.res.body = self.req.content_type + " is an unknown request content type"

            else:
                #Step[2a]: Retrieve entities matching the filter provided
                var, self.res.status_int = self.jungler.channel_get_filtered_entities(self.path_url, jBody)

        else:
            #Step[2b]: Retrieve all the entities
            var, self.res.status_int = self.jungler.channel_get_all_entities(self.path_url, "")

        #Step[3]: Adapt the response to the format defined in the Accept-Type header

        if self.res.status_int == return_code['OK']:

            self.res_adapter.convert_response_entity_multi_x_occi_location_content(var, self.res)

        else:
            self.res.content_type = "text/html"
            self.res.body = str(var)

        return self.res

    def put(self):
        """
        Fully update the mixin collection of entities

        """

        #Step[1]: Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)

        jBody = self.req_adapter.convert_request_category_content(self.req)

        if jBody is None:
            self.res.status_int = return_code['Not Acceptable']
            self.res.body = self.req.content_type + " is an unknown request content type"
        else:

            #Step[2]: Fully update the mixin collection of entities

            self.res.body, self.res.status_int = self.jungler.channel_put_multi(jBody, self.path_url)

        return self.res

    def delete(self):
        """
        Dissociates a resource instance from a mixin or delete all resource under a path

        """

        #Step[1]: Detect the body type (HTTP ,OCCI:JSON or OCCI+JSON)
        if  self.req.content_type == 'text/occi' or (
            self.req.body != ""):

            jBody = self.req_adapter.convert_request_category_content(self.req)

            if jBody is None:
                self.res.status_int = return_code['Not Acceptable']
                self.res.body = self.req.content_type + " is an unknown request content type"

                #Step[2a]: This is a dissociate mixin request
                self.res.body, self.res.status_int = self.jungler.channel_delete_multi(jBody, self.path_url)
        else:
                #Step[2b]: This is a delete on path request:
                self.jungler_p.channel_delete_on_path(self.path_url)

        return self.res
Example #9
0
class MultiEntityJungler(object):
    """
    Handles requests concerning multiple entities

    """
    def __init__(self):

        self.manager_r = ResourceManager()
        self.manager_l = LinkManager()
        self.jungler_p = PathManager()
        self.rd_baker = ResourceDataBaker()
        self.PostMan = PostMan()

    def channel_post_multi_resources(self, jreq, req_path):
        """
        Identifies the post path's goal : create a resource instance or update a mixin collection
        Args:
            @param jreq: Body content of the post request
            @param req_path: Address to which this post request was sent
        """
        #Step[1]: detect the goal of the request

        if jreq.has_key('resources') or jreq.has_key('links'):
            is_kind_loc = True
        else:
            is_kind_loc = False

        if is_kind_loc is True:

            #Step[2a]: This is a create new resources request

            db_occi_ids_locs = self.rd_baker.bake_to_post_multi_resources_2a()

            #Step[3a]: Look for the default attributes to complete the attribute description of the resource:
            default_attributes = self.rd_baker.bake_to_get_default_attributes(
                req_path)

            if db_occi_ids_locs is None or default_attributes is None:
                return "An error has occurred, please check log for more details", return_code[
                    'Internal Server Error']
            else:

                #Step[4a]: Ask the managers to create the new resources

                if jreq.has_key('resources'):
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on kind path to create a new resource channeled"
                    )
                    new_resources, resp_code_r = self.manager_r.register_resources(
                        jreq['resources'], req_path, db_occi_ids_locs,
                        default_attributes)
                else:
                    new_resources = list()
                    resp_code_r = return_code['OK, and location returned']

                if jreq.has_key('links'):
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on kind path to create a new link channeled"
                    )
                    new_links, resp_code_l = self.manager_l.register_links_explicit(
                        jreq['links'], req_path, db_occi_ids_locs,
                        default_attributes)
                else:
                    new_links = list()
                    resp_code_l = return_code['OK, and location returned']

                if resp_code_r is not return_code['OK, and location returned']\
                or resp_code_l is not return_code['OK, and location returned']:
                    return "An error has occurred, please check log for more details", return_code[
                        'Bad Request']

                #Step[5a]: Save the new resources
                entities = new_resources + new_links

                self.PostMan.save_registered_docs_in_db(entities)
                logger.debug(
                    "===== Channel_post_multi_resources ==== : Finished (2a) with success"
                )

                locations = list()

                for item in entities:
                    locations.append(item['OCCI_Location'])

                backend_m.create_entities(entities)

                return locations, return_code['OK, and location returned']

                #Step[2b]: This is an associate mixins to resources request

        elif jreq.has_key('X-OCCI-Location'):

            #Step[3b]: Get the necessary data from DB
            nb_res, mix_id = self.rd_baker.bake_to_post_multi_resources_2b(
                req_path)

            if nb_res is None:
                return "An error has occurred, please check log for more details", return_code[
                    'Internal Server Error']
            elif nb_res is 0:
                return "An error has occurred, please check log for more details", return_code[
                    'Not Found']
            else:
                to_search_for = jreq['X-OCCI-Location']

                db_docs = self.rd_baker.bake_to_post_multi_resources_2b2(
                    to_search_for)

                if db_docs is 0:
                    return "An error has occurred, please check log for more details", return_code[
                        'Not Found']

                elif db_docs is None:
                    return "An error has occurred, please check log for more details", return_code[
                        'Internal Server Error']

                else:
                    #Step[4b]: Ask the managers to associate mixins to resources
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on mixin path to associate a mixin channeled"
                    )
                    updated_entities, resp_code_e = associate_entities_to_a_mixin(
                        mix_id, db_docs)

                    self.PostMan.save_updated_docs_in_db(updated_entities)
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Finished (2b) with success"
                    )
                    backend_m.update_entities(db_docs, updated_entities)
                    return "", return_code['OK']
        else:
            return "An error has occurred, please check log for more details", return_code[
                'Bad Request']

    def channel_get_all_entities(self, req_path, jreq):
        """
        Retrieve all entities belonging to a kind or a mixin or get on a path

        Args:
            @param req_path: Address to which this post request was sent
            @param jreq: Data provided for filtering
        """

        #Step[1]: Retrieve the kind/mixin from DB

        res = self.rd_baker.bake_to_channel_get_all_entities(req_path)

        if res is None:
            return "An error has occurred, please check log for more details", return_code[
                'Internal Server Error']

        elif res is 0:

            logger.warning(
                "===== Channel_get_all_multi_entities ===== : This is a get on a path "
                + req_path)
            #Step[1b]: Get on path to retrieve the entities under that path
            var, resp_code = self.jungler_p.channel_get_on_path(req_path, jreq)
            return var, resp_code

        else:
            q = res.first()
            #Step[2]: Retrieve the entities related to the kind/mixin
            entities = self.rd_baker.bake_to_get_all_entities(
                q['value'][1], q['value'][0])
            if entities is None:
                return "An error has occurred, please check log for more details", return_code[
                    'Internal Server Error']

            else:

                logger.debug(
                    "===== Channel_get_all_entities ==== : Finished with success"
                )
                return entities, return_code['OK']

    def channel_get_filtered_entities(self, req_path, terms):
        """
        Retrieve entities belonging to a kind or a mixin matching the terms specified or get entities on a path with filtering
        Args:
            @param req_path: Address to which this post request was sent
            @param terms: Terms to filter entities
        """
        #Step[1]: Get all the entities related to kind/mixin or get on a path with filtering
        entities, ok = self.channel_get_all_entities(req_path, terms)

        if ok == return_code['OK']:
            #Note: We now need the resources OCCI descriptions so we go back to the database
            descriptions_res, descriptions_link = self.rd_baker.bake_to_get_filtered_entities(
                entities)

            if descriptions_res is None:
                return "An error has occurred, please check log for more details", return_code[
                    'Internal Server Error']
            else:
                #Step[2]: Ask the managers to do the filtering
                if terms.has_key('resources'):
                    logger.debug(
                        "===== Channel_get_filtered: Resources are sent to filter ====="
                    )
                    filtered_res, resp_code_r = self.manager_r.get_filtered_resources(
                        terms['resources'], descriptions_res)
                else:
                    logger.debug(
                        "===== Channel_get_filtered: No Resource filter =====")
                    filtered_res = list()
                    resp_code_r = return_code['OK']

                if terms.has_key('links'):
                    logger.debug(
                        "===== Channel_get_filtered: Links are sent to filter ====="
                    )
                    filtered_links, resp_code_l = self.manager_l.get_filtered_links(
                        terms['links'], descriptions_link)
                else:
                    logger.debug(
                        "===== Channel_get_filtered: No Links filter =====")
                    filtered_links = list()
                    resp_code_l = return_code['OK']

                if resp_code_l is not return_code[
                        'OK'] or resp_code_r is not return_code['OK']:
                    return "An error has occurred, please check log for more details", return_code[
                        'Bad Request']

                result = filtered_res + filtered_links

                logger.debug(
                    "===== Channel_get_filtered_entities ==== : Finished with success"
                )

                return result, return_code['OK']

    def channel_put_multi(self, jreq, req_url):
        """
        Update the mixin collection of resources
        Args:

            @param jreq: OCCI_Locations of the resources
            @param req_url: URL of the request
        """

        #Step[1]: Get the necessary data from DB

        nb_res, mix_id = self.rd_baker.bake_to_post_multi_resources_2b(req_url)
        if nb_res is None:
            return "An error has occurred, please check log for more details", return_code[
                'Internal Server Error']
        elif nb_res is 0:
            return "An error has occurred, please check log for more details", return_code[
                'Not Found']
        else:
            to_search_for = jreq['X-OCCI-Location']
            db_docs = self.rd_baker.bake_to_post_multi_resources_2b2(
                to_search_for)

            if db_docs is 0:
                return "An error has occurred, please check log for more details", return_code[
                    'Not Found']

            elif db_docs is None:
                return "An error has occurred, please check log for more details", return_code[
                    'Internal Server Error']

            else:
                #Step[2]: Ask the managers to associate mixins to resources
                logger.debug(
                    "===== Channel_put_multi_resources ==== : Put on mixin path to associate a mixin channeled"
                )
                updated_entities, resp_code_e = associate_entities_to_a_mixin(
                    mix_id, db_docs)

                self.PostMan.save_updated_docs_in_db(updated_entities)

                logger.debug(
                    "===== Channel_put_multi_resources ==== : Finished (2b) with success"
                )
                backend_m.update_entities(db_docs, updated_entities)
                return "", return_code['OK']

    def channel_delete_multi(self, jreq, req_url):
        """
        Remove the mixin from the resources
        Args:
            @param jreq: OCCI_Locations of the resources
            @param req_url: URL of the request
        """

        #Step[1]: Get the necessary data from DB

        nb_res, mix_id = self.rd_baker.bake_to_post_multi_resources_2b(req_url)
        if nb_res is None:
            return "An error has occurred, please check log for more details", return_code[
                'Internal Server Error']

        elif nb_res is 0:
            return "An error has occurred, please check log for more details", return_code[
                'Not Found']

        else:
            to_search_for = jreq['X-OCCI-Location']
            db_docs = self.rd_baker.bake_to_post_multi_resources_2b2(
                to_search_for)

            if db_docs is 0:
                return "An error has occurred, please check log for more details", return_code[
                    'Not Found']

            elif db_docs is None:
                return "An error has occurred, please check log for more details", return_code[
                    'Internal Server Error']

            else:
                logger.debug(
                    " ===== Delete_multi_entities : Delete on mixin to Dissociate mixins channeled ====="
                )
                updated_entities, resp_code_e = dissociate_entities_from_a_mixin(
                    mix_id, db_docs)

            if resp_code_e is not return_code['OK']:
                return "An error has occurred, please check log for more details", return_code[
                    'Bad Request']

            self.PostMan.save_updated_docs_in_db(updated_entities)

            backend_m.update_entities(db_docs, updated_entities)

            return "", return_code['OK']

    def channel_trigger_actions(self, jBody, req_url, triggered_action):
        """
        Trigger action on a collection of resources related to a kind or mixin
        Args:
            @param jBody: Action provided
            @param req_url: URL of the request
            @param triggered_action: Action name
        """

        #Step[1]: Get the necessary data:

        kind_ids, entities = self.rd_baker.bake_to_channel_trigger_actions(
            req_url)

        if kind_ids is None:
            return "An error has occurred, please check log for more details", return_code[
                'Internal Server Error']
        if kind_ids is 0:
            return "An error has occured, please check log for more details", return_code[
                'Not Found']
        else:
            providers = list()
            #Step[2]: Get the providers of the instances
            for item in kind_ids:
                provider = self.rd_baker.bake_to_get_provider(item)
                providers.append(provider)

            if jBody.has_key('attributes') is True:

                parameters = jBody['attributes']
            else:
                parameters = None

            #Step[3]: Ask the backend to trigger the action on the resources
            backend_m.trigger_action_on_multi_resource(entities, providers,
                                                       jBody['actions'][0],
                                                       parameters)

            return "", return_code['OK']
class MultiEntityJungler(object):
    """

    """

    def __init__(self):
        self.manager_r = ResourceManager()
        self.manager_l = LinkManager()
        self.jungler_p = PathManager()
        self.rd_baker = ResourceDataBaker()
        self.PostMan = PostMan()

    def channel_post_multi_resources(self, jreq, req_path):
        """
        Identifies the post path's goal : create a resource instance or update a mixin collection
        Args:
            @param jreq: Body content of the post request
            @param req_path: Address to which this post request was sent
        """
        #Step[1]: detect the request's goal

        if jreq.has_key('resources') or jreq.has_key('links'):
            is_kind_loc = True
        else:
            is_kind_loc = False

        if is_kind_loc is True:
            #Step[2a]: This is a create new resources request
            db_occi_ids_locs = self.rd_baker.bake_to_post_multi_resources_2a()
            default_attributes = self.rd_baker.bake_to_get_default_attributes(req_path)

            if db_occi_ids_locs is None or default_attributes is None:
                return "An error has occurred, please check log for more details", return_code['Internal Server Error']
            else:
                #Look for the default attributes to complete the attribute description of the resource:

                if jreq.has_key('resources'):
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on kind path to create a new resource channeled")
                    new_resources, resp_code_r = self.manager_r.register_resources(jreq['resources'], req_path,
                        db_occi_ids_locs, default_attributes)
                else:
                    new_resources = list()
                    resp_code_r = return_code['OK, and location returned']

                if jreq.has_key('links'):
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on kind path to create a new link channeled")
                    new_links, resp_code_l = self.manager_l.register_links_explicit(jreq['links'], req_path,
                        db_occi_ids_locs)
                else:
                    new_links = list()
                    resp_code_l = return_code['OK, and location returned']

                if resp_code_r is not return_code['OK, and location returned']\
                or resp_code_l is not return_code['OK, and location returned']:
                    return "An error has occurred, please check log for more details", return_code['Bad Request']

                #Step[3a]: Save the new resources
                entities = new_resources + new_links

                self.PostMan.save_registered_docs_in_db(entities)
                logger.debug("===== Channel_post_multi_resources ==== : Finished (2a) with success")

                locations = list()

                for item in entities:
                    locations.append(item['OCCI_Location'])
                    #return the locations of the resources

                backend_m.create_entities(entities, locations)

                return locations, return_code['OK, and location returned']

                #Step[2b]: This is an associate mixins to resources request

        elif jreq.has_key('X-OCCI-Location'):
            nb_res, mix_id = self.rd_baker.bake_to_post_multi_resources_2b(req_path)

            if nb_res is None:
                return "An error has occurred, please check log for more details", return_code['Internal Server Error']
            elif nb_res is 0:
                return "An error has occurred, please check log for more details", return_code['Not Found']
            else:
                to_search_for = jreq['X-OCCI-Location']

                db_docs = self.rd_baker.bake_to_post_multi_resources_2b2(to_search_for)

                if db_docs is 0:
                    return "An error has occurred, please check log for more details", return_code['Not Found']

                elif db_docs is None:
                    return "An error has occurred, please check log for more details", return_code[
                                                                                       'Internal Server Error']

                else:
                    #Step[3b]: Treat the data to associate mixins to resources
                    logger.debug(
                        "===== Channel_post_multi_resources ==== : Post on mixin path to associate a mixin channeled")
                    updated_entities, resp_code_e = associate_entities_to_a_mixin(mix_id, db_docs)

                    self.PostMan.save_updated_docs_in_db(updated_entities)
                    logger.debug("===== Channel_post_multi_resources ==== : Finished (2b) with success")
                    backend_m.update_entities(db_docs, updated_entities)
                    return "", return_code['OK']
        else:
            return "An error has occurred, please check log for more details", return_code['Bad Request']

    def channel_get_all_entities(self, req_path, jreq):
        """
        retrieve all entities belonging to a kind or a mixin
        Args:
            @param req_path: Address to which this post request was sent
            @param jreq: Data provided for filtering
        """
        res = self.rd_baker.bake_to_channel_get_all_entities(req_path)

        if res is None:
            return "An error has occurred, please check log for more details", return_code['Internal Server Error']
        elif res is 0:
            # Retrieve the state of the name space hierarchy
            logger.warning("===== Channel_get_all_multi_entities ===== : This is a get on a path " + req_path)

            var, resp_code = self.jungler_p.channel_get_on_path(req_path, jreq)
            return var, resp_code

        else:
            q = res.first()
            entities = self.rd_baker.bake_to_get_all_entities(q['value'][1], q['value'][0])
            if entities is None:
                return "An error has occurred, please check log for more details", return_code['Internal Server Error']

            else:
                #backend_m.read_entities(occi_descriptions)
                logger.debug("===== Channel_get_all_entities ==== : Finished with success")
                return entities, return_code['OK']

    def channel_get_filtered_entities(self, req_path, terms):
        """
        Retrieve entities belonging to a kind or a mixin matching the terms specified
        Args:
            @param req_path: Address to which this post request was sent
            @param terms: Terms to filter entities
        """
        entities, ok = self.channel_get_all_entities(req_path, terms)
        if ok == return_code['OK']:
            descriptions_res, descriptions_link = self.rd_baker.bake_to_get_filtered_entities(entities)

            if descriptions_res is None:
                return "An error has occurred, please check log for more details", return_code['Internal Server Error']
            else:
                if terms.has_key('resources'):
                    logger.debug("===== Channel_get_filtered: Resources are sent to filter =====")
                    filtered_res, resp_code_r = self.manager_r.get_filtered_resources(terms['resources'],
                        descriptions_res)
                else:
                    logger.debug("===== Channel_get_filtered: No Resource filter =====")
                    filtered_res = list()
                    resp_code_r = return_code['OK']

                if terms.has_key('links'):
                    logger.debug("===== Channel_get_filtered: Links are sent to filter =====")
                    filtered_links, resp_code_l = self.manager_l.get_filtered_links(terms['links'], descriptions_link)
                else:
                    logger.debug("===== Channel_get_filtered: No Links filter =====")
                    filtered_links = list()
                    resp_code_l = return_code['OK']

                if resp_code_l is not return_code['OK'] or resp_code_r is not return_code['OK']:
                    return "An error has occurred, please check log for more details", return_code['Bad Request']

                result = filtered_res + filtered_links

                logger.debug("===== Channel_get_filtered_entities ==== : Finished with success")
                #occi_descriptions = self.rd_baker.bake_to_get_filtered_entities_2(result)

                #backend_m.read_entities(occi_descriptions)
                return result, return_code['OK']


    def channel_put_multi(self, jreq, req_url):
        """
        Update the mixin collection of resources
        Args:

            @param jreq: OCCI_Locations of the resources
            @param req_url: URL of the request
        """
        return "This method is under reconstruction", return_code['Not Implemented']

    #        database = config.prepare_PyOCNI_db()
    #
    #        if jreq.has_key('Resource_Locations') and jreq.has_key('Mixin_Locations'):
    #            url_path = joker.reformat_url_path(req_url)
    #            db_docs = list()
    #            to_validate = jreq['Mixin_Locations']
    #            to_validate.append(url_path)
    #            mix_ids = list()
    #            for occi_loc in to_validate:
    #                try:
    #                    query = database.view('/db_views/my_mixins',key = occi_loc)
    #                except Exception as e:
    #                    logger.error("Associate mixins : " + e.message)
    #                    return "An error has occurred, please check log for more details",return_code['Internal Server Error']
    #                if query.count() is 0:
    #                    logger.error("Associate mixins : " + occi_loc)
    #                    return "An error has occurred, please check log for more details",return_code['Internal Server Error']
    #                else:
    #                    mix_ids.append(query.first()['value'])
    #
    #            to_search_for = jreq['Resource_Locations']
    #            for item in to_search_for:
    #                try:
    #                    query = database.view('/db_views/for_associate_mixin',key=[item,user_id])
    #                except Exception as e:
    #                    logger.error("Associate mixins : " + e.message)
    #                    return "An error has occurred, please check log for more details",return_code['Internal Server Error']
    #                if query.count() is 0:
    #                    logger.error("Associate mixins  : " + item)
    #                    return "An error has occurred, please check log for more details",return_code['Not Found']
    #                else:
    #                    q = query.first()
    #                    db_docs.append(q['value'])
    #
    #            logger.debug("Post path : Post on mixin path to associate mixins channeled")
    #            updated_entities,resp_code_e = associate_entities_to_mixins(mix_ids,db_docs)
    #        else:
    #            updated_entities = list()
    #            resp_code_e = return_code['Bad Request']
    #
    #        if resp_code_e is not return_code['OK']:
    #            return "An error has occurred, please check log for more details",return_code['Bad Request']
    #
    #        database.save_docs(updated_entities,force_update=True,all_or_nothing=True)
    #        backend_m.update_entities(db_docs,updated_entities)
    #        return "",return_code['OK']

    def channel_delete_multi(self, jreq, req_url):
        """
        Update the mixin collection of resources
        Args:
            @param jreq: OCCI_Locations of the resources
            @param req_url: URL of the request
        """
        return "This method is under reconstruction", return_code['Not Implemented']

    #        if jreq.has_key('X-OCCI-Location'):
    #
    #            url_path = joker.reformat_url_path(req_url)
    #            db_docs = list()
    #
    #            try:
    #                query = database.view('/db_views/my_mixins',key = url_path)
    #            except Exception as e:
    #                logger.error("Dissociate mixins : " + e.message)
    #                return "An error has occurred, please check log for more details",return_code['Internal Server Error']
    #
    #
    #            mix_id = query.first()['value']
    #
    #            to_search_for = jreq['X-OCCI-Location']
    #            for item in to_search_for:
    #                try:
    #                    query = database.view('/db_views/for_associate_mixin',key=item)
    #                except Exception as e:
    #                    logger.error("Associate mixins : " + e.message)
    #                    return "An error has occurred, please check log for more details",return_code['Internal Server Error']
    #                if query.count() is 0:
    #                    logger.error("Associate mixins  : " + item)
    #                    return "An error has occurred, please check log for more details",return_code['Not Found']
    #                else:
    #                    q = query.first()
    #                    db_docs.append(q['value'])
    #
    #            logger.debug("Delete path: delete on mixin path to Dissociate mixins channeled")
    #            updated_entities,resp_code_e = dissociate_entities_from_a_mixin(mix_id,db_docs)
    #        else:
    #            updated_entities = list()
    #            resp_code_e = return_code['Bad Request']
    #
    #        if resp_code_e is not return_code['OK']:
    #            return "An error has occurred, please check log for more details",return_code['Bad Request']
    #
    #        database.save_docs(updated_entities,force_update=True,all_or_nothing=True)
    #        backend_m.update_entities(db_docs,updated_entities)
    #        return "",return_code['OK']

    def channel_trigger_actions(self, jBody, req_url, triggered_action):
        """
        Trigger action on a collection of kind or mixin
        Args:
            @param jBody: Action provided
            @param req_url: URL of the request
            @param triggered_action: Action name
        """

        kind_ids, entities = self.rd_baker.bake_to_channel_trigger_actions(req_url)
        # Get OCCI_ID from OCCI_Location

        if kind_ids is None:
            return "An error has occurred, please check log for more details", return_code['Internal Server Error']
        if kind_ids is 0:
            return "An error has occured, please check log for more details", return_code['Not Found']
        else:
            providers = list()
            for item in kind_ids:
                provider = self.rd_baker.bake_to_get_provider(item)
                providers.append(provider)

            backend_m.trigger_action_on_multi_resource(entities, providers, jBody['action'][0])

            return "", return_code['OK']