Example #1
0
// CreateResource creates an instance of the resource associated with
// the request url, writes the body of the request into the new object,
// and then persists the object in the database. A unique identifier is
// created and associated with the object. A copy of the object that was
// stored in the database is returned in the response.
func (rc *ResourceController) CreateResource(ctx *gin.Context) {
	req := ctx.Request
	resourceType := getResourceType(req.URL)
	resource := ptm_models.NewStructForResourceName(resourceType)
	if err := ctx.Bind(resource); err != nil {
		ctx.AbortWithError(http.StatusBadRequest, err)
		return
	}

	res, err := ptm_models.PersistResource(rc.Database(), resourceType, resource)
	if err != nil {
		ctx.AbortWithError(http.StatusInternalServerError, err)
		return
	}

	id := reflect.ValueOf(res).Elem().FieldByName("ID").String()

	logger.Log.WithFields(
		logrus.Fields{"res type": resourceType, "id": id}).Info("CreateResource")

	ctx.Header("Location", responseURL(req, resourceType, id).String())

	ctx.JSON(http.StatusCreated, res)
}
func (s *ServerSuite) TestRecordMatchRunResponse(c *C) {
	var r interface{}
	// Insert a record match run object to the DB
	//	r := ptm_models.InsertResourceFromFile(Database(), "RecordMatchRun", "../fixtures/record-match-run-01.json")
	recMatchRun := &ptm_models.RecordMatchRun{}
	ptm_models.LoadResourceFromFile("../fixtures/record-match-run-01.json", recMatchRun)
	//	recMatchRun := r.(*ptm_models.RecordMatchRun)
	c.Assert(*recMatchRun, NotNil)
	// confirm initial state - zero responses assoc. w/ run
	c.Assert(len(recMatchRun.Responses), Equals, 0)
	// Assign New Identifier to request message
	//	recMatchRun.Request.Message.Enry[0].Resource.ID = bson.NewObjectId()
	reqMsg := recMatchRun.Request.Message
	reqMsgHdr := reqMsg.Entry[0].Resource.(*fhir_models.MessageHeader)
	recMatchRun.Request.ID = bson.NewObjectId()
	reqMsg.Id = bson.NewObjectId().Hex()
	reqMsgHdr.Id = bson.NewObjectId().Hex()

	ptm_models.PersistResource(Database(), "RecordMatchRun", recMatchRun)

	logger.Log.WithFields(
		logrus.Fields{"func": "TestRecordMatchRunResponse",
			"recMatchRun": recMatchRun}).Info("after insert recMatchRun")

	respMsg := &fhir_models.Bundle{}
	// Load text of a record match ack message
	ptm_models.LoadResourceFromFile("../fixtures/record-match-ack-01.json", respMsg)
	//respMsg := r.(*fhir_models.Bundle)
	c.Assert(*respMsg, NotNil)

	// Ensure the response references the request
	//	reqMsg := recMatchRun.Request.Message
	c.Assert(reqMsg, NotNil)
	c.Assert(reqMsg.Type, Equals, "message")
	c.Assert(len(reqMsg.Entry) > 1, Equals, true)
	c.Assert(reqMsg.Entry[0].Resource, NotNil)
	//	reqMsgHdr := reqMsg.Entry[0].Resource.(*fhir_models.MessageHeader)
	respMsgHdr := respMsg.Entry[0].Resource.(*fhir_models.MessageHeader)
	respMsgHdr.Response.Identifier = reqMsgHdr.Id

	buf, _ := respMsg.MarshalJSON()
	logger.Log.WithFields(
		logrus.Fields{"func": "TestRecordMatchRunResponse",
			"resp msg": string(buf)}).Info("prep to POST")

	e := s.Server.Engine

	code, body := request("POST", "/Bundle",
		bytes.NewReader(buf), "application/json", e)
	c.Assert(code, Equals, http.StatusCreated)
	c.Assert(body, NotNil)
	logger.Log.Info("Post Record Match response: " + body)

	// Load the record match run object -- this time from database
	r, err := ptm_models.LoadResource(Database(), "RecordMatchRun", recMatchRun.ID)
	c.Assert(err, IsNil)
	c.Assert(r, NotNil)
	recMatchRun = r.(*ptm_models.RecordMatchRun)

	logger.Log.WithFields(
		logrus.Fields{"func": "TestRecordMatchRunResponse",
			"recMatchRun": recMatchRun}).Info("after recv response")

	// The response should be attached to the record match run ObjectId
	c.Assert(len(recMatchRun.Responses), Equals, 1)
	c.Assert(recMatchRun.Responses[0].ID, NotNil)
	c.Assert(recMatchRun.Responses[0].Message, NotNil)
	var respMsg1 *fhir_models.Bundle
	respMsg1 = recMatchRun.Responses[0].Message

	// After inserting into database, we've lost knowledge about type of resource in response message
	// so we use hack to decode to and then encode from json to get map to struct
	respMsgHdr1 := &fhir_models.MessageHeader{}
	mapToStruct(respMsg1.Entry[0].Resource.(bson.M), respMsgHdr1)
	c.Assert(respMsgHdr1.Response.Identifier, Equals, respMsgHdr.Response.Identifier)
}
Example #3
0
// CreateRecordMatchRunHandler creates a HandlerFunc that creates a new
// RecordMatchRun and constructs and sends a Record Match request message.
func CreateRecordMatchRunHandler(provider func() *mgo.Database) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		recMatchRun := &ptm_models.RecordMatchRun{}
		if err := ctx.Bind(recMatchRun); err != nil {
			ctx.AbortWithError(http.StatusInternalServerError, err)
			return
		}

		if !isValidRecordMatchRun(recMatchRun) {
			// Bad Request: Record Match Run contains invalid content
			ctx.String(http.StatusBadRequest, "Invalid RecordMatchRun content")
			ctx.Abort()
			return
		}

		// retrieve and validate the record match context
		recMatchContextID := recMatchRun.RecordMatchContextID
		logger.Log.WithFields(
			logrus.Fields{"method": "CreateRecordMatchRun",
				"recMatchContextID": recMatchContextID}).Debug("check recmatch config id")
		if !recMatchContextID.Valid() {
			// Bad Request: Record Match Context is optional but must be valid, if provided
			ctx.String(http.StatusBadRequest, "Invalid RecordMatchContextID")
			ctx.Abort()
			return
		}

		// Retrieve the info about the record matcher
		obj, err := ptm_models.LoadResource(provider(), "RecordMatchSystemInterface",
			recMatchRun.RecordMatchSystemInterfaceID)
		if err != nil {
			ctx.String(http.StatusBadRequest, "Unable to find Record Match System Interface")
			ctx.Abort()
			return
		}
		recMatchSysIface := obj.(*ptm_models.RecordMatchSystemInterface)
		if !isValidRecordMatchSysIface(recMatchSysIface) {
			ctx.String(http.StatusBadRequest, "Invalid Record Match System Interface")
			ctx.Abort()
			return
		}

		// construct a record match request
		reqMatchRequest, err := newRecordMatchRequest(recMatchSysIface.ResponseEndpoint, recMatchRun, provider())
		if err != nil {
			logger.Log.WithFields(
				logrus.Fields{"method": "CreateRecordMatchRun",
					"err": err}).Warn("Unable to create Record Match Request")
			ctx.AbortWithError(http.StatusBadRequest, err)
			return
		}
		// attach the request message to the run object
		recMatchRun.Request = *reqMatchRequest

		// Construct body of the http request for the record match request
		reqBody, _ := reqMatchRequest.Message.MarshalJSON()

		svrEndpoint := prepEndpoint(recMatchSysIface.ServerEndpoint, reqMatchRequest.Message.Id)

		logger.Log.WithFields(
			logrus.Fields{"method": "CreateRecordMatchRun",
				"server endpoint": svrEndpoint,
				"reqBody":         string(reqBody[:]),
				"message":         reqMatchRequest.Message}).Info("About to submit request")

		reqMatchRequest.SubmittedOn = time.Now()

		// Send the record match request to a FHIR server acting as msg broker.
		resp, err := ptm_http.Put(svrEndpoint, "application/json+fhir",
			bytes.NewReader(reqBody))
		if err != nil {
			// HACK In this configuration, the test harness only supports itself as the FHIR message broker
			if resp.StatusCode == 302 {
				logger.Log.Debug("CreateRecordMatchRun: redirect detected - Infer server is in Heart mode")
				_, err = ptm_models.PersistFhirResource(provider(), "Bundle", reqMatchRequest.Message)
				if err != nil {
					ctx.AbortWithError(http.StatusInternalServerError, err)
					return
				}
			} else {
				logger.Log.WithFields(
					logrus.Fields{"method": "CreateRecordMatchRun",
						"err": err}).Warn("Sending Record Match Request")
				ctx.AbortWithError(http.StatusInternalServerError, err)
				return
			}
		}
		logger.Log.WithFields(
			logrus.Fields{"method": "CreateRecordMatchRun",
				"status": resp.StatusCode}).Info("Put Response Status")

		// Store status, Sent, with the run object
		recMatchRun.Status = make([]ptm_models.RecordMatchRunStatusComponent, 1)
		recMatchRun.Status[0].CreatedOn = time.Now()
		// if a success code was received
		if resp.StatusCode >= 200 && resp.StatusCode < 300 {
			recMatchRun.Status[0].Message = "Request Sent [" + resp.Status + "]"
		} else if resp.StatusCode == 302 {
			recMatchRun.Status[0].Message = "Redirect from Msg Broker Not Supported; Request persisted in local database"
		} else {
			recMatchRun.Status[0].Message = "Error Sending Request to Record Matcher [" + resp.Status + "]"
		}

		// Persist the record match run
		resource, err := ptm_models.PersistResource(provider(), "RecordMatchRun", recMatchRun)
		if err != nil {
			ctx.AbortWithError(http.StatusInternalServerError, err)
			return
		}

		ctx.JSON(http.StatusCreated, resource)
	}
}