public void deleteCustomField(CustomField field) throws ApplicationException {
   if (field == null
       || ConvertUtil.isNullOrEmpty(field.getEntityName())
       || ConvertUtil.isNullOrEmpty(field.getFieldName())) {
     log.warn("The custom field to be deleted is invalid: " + field);
     throw new ApplicationException("Unable to add invalid custom field definition.");
   }
   Entity entity = findLatestEntityVersionByName(field.getEntityName());
   EntityAttribute attrib = null;
   for (EntityAttribute item : entity.getAttributes()) {
     if (item.getName().equalsIgnoreCase(field.getFieldName()) && item.getDateVoided() == null) {
       attrib = item;
     }
   }
   if (attrib == null) {
     log.info("The user attempted to delete a custom field that does not exist.");
     throw new ApplicationException("Unable to delete an unknown custom field definition.");
   }
   attrib.setDateVoided(new Date());
   attrib.setUserVoidedBy(Context.getUserContext().getUser());
   try {
     entityDefinitionDao.updateEntity(entity);
     // Generate a notification event to inform interested listeners via the lightweight mechanism
     // that this event has occurred.
     Context.notifyObserver(ObservationEventType.CUSTOM_FIELD_DELETE_EVENT, field);
   } catch (DaoException e) {
     log.error("Failed while deleting a custom field: " + e, e);
     throw new ApplicationException("Failed while deleting the custom field: " + e.getMessage());
   }
 }
  public Entity addEntity(Entity entity) throws ApplicationException {
    if (entity == null) {
      return null;
    }

    if (entity.getEntityVersionId() != null) {
      throw new ApplicationException(
          "This entity definition already exists so it can only be updated.");
    }

    validateNameUniqueness(entity);
    try {
      entity.setUserCreatedBy(Context.getUserContext().getUser());
      Date dateCreated = new Date();
      entity.setDateCreated(dateCreated);
      for (EntityAttribute attribute : entity.getAttributes()) {
        attribute.setDateCreated(dateCreated);
        attribute.setUserCreatedBy(Context.getUserContext().getUser());
        attribute.setEntity(entity);
      }
      entityDefinitionDao.addEntity(entity);
      addToCache(entity);
      Context.notifyObserver(ObservationEventType.ENTITY_ADD_EVENT, entity);
      return entity;
    } catch (DaoException e) {
      throw new ApplicationException(e.getMessage());
    }
  }
  public void updateEntityAttributeValidations(
      List<EntityAttributeValidation> validations, Entity updatedEntity, String attributeName)
      throws ApplicationException {
    if (validations == null) {
      return;
    }

    Entity existing = entityDefinitionDao.loadEntity(updatedEntity.getEntityVersionId());
    EntityAttribute existingAttribute = existing.findAttributeByName(attributeName);
    List<EntityAttributeValidation> existingValidations =
        loadEntityAttributeValidations(existingAttribute);

    Map<Integer, EntityAttributeValidation> newValidationById =
        new HashMap<Integer, EntityAttributeValidation>();
    for (EntityAttributeValidation validation : validations) {
      if (validation.getEntityAttributeValidationId() != null) {
        newValidationById.put(validation.getEntityAttributeValidationId(), validation);
      }
    }

    // remove deleted validations
    for (EntityAttributeValidation validation : existingValidations) {
      if (newValidationById.get(validation.getEntityAttributeValidationId()) == null) {
        deleteEntityAttributeValidation(validation);
      }
    }

    for (EntityAttributeValidation newValidation : validations) {
      if (newValidation.getEntityAttributeValidationId() != null) {
        updateEntityAttributeValidation(newValidation);
      } else {
        addEntityAttributeValidation(newValidation);
      }
    }
  }
 public Entity loadEntityByName(String entityName) {
   @SuppressWarnings("unchecked")
   List<Object> keys = entityDefinitionCache.getKeys();
   for (Object key : keys) {
     Entity entity = getFromCache((Integer) key);
     if (entity.getName().equals(entityName)) {
       return entity;
     }
   }
   Entity entity = findLatestEntityVersionByName(entityName);
   return entity;
 }
  private void addToCache(Entity entity) {
    if (!entityDefinitionCache.getStatus().equals(Status.STATUS_ALIVE)) {
      return;
    }

    Element element = entityDefinitionCache.get(entity.getEntityVersionId());
    if (element != null) {
      log.debug("Updating an entity definition entry in the cache: " + entity);
    } else {
      log.debug("Adding an entity definition entry in the cache: " + entity);
    }
    element = new Element(entity.getEntityVersionId(), entity);
    entityDefinitionCache.put(element);
  }
  /** Will export the entity passed in as the entity version id into a string. */
  public String exportEntity(Integer entityVersionId) throws ApplicationException {
    if (entityVersionId == null) {
      return "";
    }

    Entity entity = entityDefinitionDao.loadEntity(entityVersionId);

    try {
      // 1. convert Entity to EntityModel
      EntityModel entityModel = ConvertUtil.mapToEntityModel(entity, EntityModel.class);

      // 2. set group info to EntityModel
      List<EntityAttributeGroup> groups = loadEntityAttributeGroups(entity);
      entityModel = ConvertUtil.setGroupInfoToEntityModel(groups, entityModel);

      // 3. set validation info to entity attribute
      for (EntityAttribute attribute : entity.getAttributes()) {
        List<EntityAttributeValidation> validations = loadEntityAttributeValidations(attribute);

        ValidationsType validationsType = ConvertUtil.mapToEntityValidations(validations);

        // set validations info to attributeType
        AttributesType attributesType = entityModel.getAttributes();
        if (attributesType != null) {
          for (AttributeType attributeType : attributesType.getAttribute()) {
            String name = attributeType.getName();

            if (attribute.getName().equals(name)) {
              attributeType.setValidations(validationsType);
            }
          }
        }
      }

      // export to xml format
      JAXBContext jaxbContext = JAXBContext.newInstance(EntityModel.class);
      Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
      jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

      OutputStream outputStream = new ByteArrayOutputStream();
      jaxbMarshaller.marshal(entityModel, outputStream);

      return outputStream.toString();
    } catch (JAXBException e) {
      log.warn("Unable to serialize a Entity into a string: " + e, e);
      throw new RuntimeException(e);
    }
  }
 private Entity findLatestEntityVersionByName(String name) {
   List<Entity> entities = findEntitiesByName(name);
   if (entities.size() == 0) {
     return null;
   }
   if (entities.size() == 1) {
     return entities.get(0);
   }
   Entity latestEntity = entities.get(0);
   for (Entity entity : entities) {
     if (entity.getEntityVersionId() > latestEntity.getEntityVersionId()) {
       latestEntity = entity;
     }
   }
   return latestEntity;
 }
  public void updateEntityAttributeGroups(List<EntityAttributeGroup> groups, Entity updatedEntity)
      throws ApplicationException {
    if (groups == null) {
      return;
    }

    Entity existing = entityDefinitionDao.loadEntity(updatedEntity.getEntityVersionId());
    List<EntityAttributeGroup> existingGroups = loadEntityAttributeGroups(existing);

    Map<Integer, EntityAttributeGroup> newGroupById = new HashMap<Integer, EntityAttributeGroup>();
    for (EntityAttributeGroup group : groups) {
      newGroupById.put(group.getEntityAttributeGroupId(), group);
    }

    // remove deleted groups
    for (EntityAttributeGroup group : existingGroups) {
      if (newGroupById.get(group.getEntityAttributeGroupId()) == null) {
        deleteEntityAttributeGroup(group);
      }
    }

    for (EntityAttributeGroup newgroup : groups) {
      if (newgroup.getEntityAttributeGroupId() != null) {
        updateEntityAttributeGroup(newgroup);
      } else {
        addEntityAttributeGroup(newgroup);
      }
    }
  }
 private void preloadCache() {
   List<Entity> entities = loadEntities();
   log.info("Pre-loaded configuration for " + entities.size() + " entities.");
   Map<String, List<CustomField>> customFieldsListByEntityName =
       new HashMap<String, List<CustomField>>();
   Map<String, Map<String, CustomField>> customFieldsMapByEntityName =
       new HashMap<String, Map<String, CustomField>>();
   for (Entity entity : entities) {
     List<CustomField> customFields = loadCustomFields(entity.getName());
     customFieldsListByEntityName.put(entity.getName(), customFields);
     log.info(
         "Pre-loaded a list of "
             + customFields.size()
             + " custom fields for entity "
             + entity.getName());
     Map<String, CustomField> customFieldMap = new HashMap<String, CustomField>();
     for (CustomField field : customFields) {
       customFieldMap.put(field.getFieldName(), field);
     }
     customFieldsMapByEntityName.put(entity.getName(), customFieldMap);
     Context.getConfiguration()
         .registerConfigurationEntry(
             entity.getName(),
             ConfigurationRegistry.CUSTOM_FIELD_LIST_BY_ENTITY_NAME_MAP,
             customFieldsListByEntityName);
     Context.getConfiguration()
         .registerConfigurationEntry(
             entity.getName(),
             ConfigurationRegistry.CUSTOM_FIELD_MAP_BY_ENTITY_NAME_MAP,
             customFieldsMapByEntityName);
   }
 }
  public CustomField addCustomField(CustomField field) throws ApplicationException {
    if (field == null
        || ConvertUtil.isNullOrEmpty(field.getEntityName())
        || ConvertUtil.isNullOrEmpty(field.getFieldName())
        || ConvertUtil.isNullOrEmpty(field.getSourceFieldName())) {
      log.info("The custom field to be added is invalid: " + field);
      throw new ApplicationException("Unable to add invalid custom field definition.");
    }

    // Validate that a custom field by the same name does not already exist.
    List<CustomField> fields = loadCustomFields(field.getEntityName());
    for (CustomField custom : fields) {
      if (custom.getFieldName().equalsIgnoreCase(field.getFieldName())) {
        log.warn(
            "User attempted to add a custom field "
                + field
                + " that already exists in the system.");
        throw new ApplicationException(
            "Unable to add a custom field that already exists in the system.");
      }
    }

    Entity entity = findLatestEntityVersionByName(field.getEntityName());
    try {
      EntityAttribute attribute = buildAttributeFromCustomField(entity, field);
      entity.addAttribute(attribute);
      // TODO: Validate that the source field is known
      // TODO: Validate that the transformation function is known
      attribute = entityDefinitionDao.addCustomField(entity, attribute);
      // Generate a notification event to inform interested listeners via the lightweight mechanism
      // that this event has occurred.
      Context.notifyObserver(ObservationEventType.CUSTOM_FIELD_ADD_EVENT, field);
      Context.notifyObserver(ObservationEventType.ENTITY_ATTRIBUTE_UPDATE_EVENT, entity);
      return field;
    } catch (DaoException e) {
      log.error("Failed while saving a custom field: " + e, e);
      throw new ApplicationException("Failed while saving the custom field: " + e.getMessage());
    }
  }
 public void deleteEntity(Entity entity) throws ApplicationException {
   if (entity == null) {
     return;
   }
   if (entity.getEntityVersionId() == null) {
     throw new ApplicationException(
         "An entity definition must first be created before it is deleted.");
   }
   try {
     Date dateVoided = new Date();
     entity.setDateVoided(dateVoided);
     entity.setUserVoidedBy(Context.getUserContext().getUser());
     for (EntityAttribute attribute : entity.getAttributes()) {
       attribute.setDateVoided(dateVoided);
       attribute.setUserVoidedBy(Context.getUserContext().getUser());
       attribute.setEntity(entity);
     }
     entityDefinitionDao.updateEntity(entity);
     addToCache(entity);
   } catch (DaoException e) {
     throw new ApplicationException(e.getMessage());
   }
 }
  public Entity updateEntity(Entity entity) throws ApplicationException {
    if (entity == null) {
      return entity;
    }
    if (entity.getEntityVersionId() == null) {
      throw new ApplicationException(
          "An entity definition must first be created before it is updated.");
    }
    try {
      Date currentDate = new Date();
      entity.setDateChanged(currentDate);
      entity.setUserChangedBy(Context.getUserContext().getUser());
      for (EntityAttribute attrib : entity.getAttributes()) {
        if (attrib.getDateCreated() == null) {
          attrib.setDateCreated(currentDate);
          attrib.setUserCreatedBy(Context.getUserContext().getUser());
          // attrib.setEntity(entity);
        }
        attrib.setEntity(entity);
      }

      // Mark deletion attributes
      handleAttributeUpdates(entity);

      // remove validations for marked attribute
      for (EntityAttribute attrib : entity.getAttributes()) {
        if (attrib.getUserVoidedBy() != null) {

          // remove validations
          List<EntityAttributeValidation> existingValidations =
              loadEntityAttributeValidations(attrib);
          for (EntityAttributeValidation validation : existingValidations) {
            deleteEntityAttributeValidation(validation);
          }
        }
      }

      Entity updatedEntity = entityDefinitionDao.updateEntity(entity);
      updatedEntity = entityDefinitionDao.loadEntity(entity.getEntityVersionId());

      addToCache(updatedEntity);
      Context.notifyObserver(ObservationEventType.ENTITY_ATTRIBUTE_UPDATE_EVENT, entity);

      return updatedEntity;
    } catch (DaoException e) {
      throw new ApplicationException(e.getMessage());
    }
  }
  private void handleAttributeUpdates(Entity entity) {
    Entity existing = entityDefinitionDao.loadEntity(entity.getEntityVersionId());

    Map<Integer, EntityAttribute> newAttribById = new HashMap<Integer, EntityAttribute>();
    for (EntityAttribute attribute : entity.getAttributes()) {
      newAttribById.put(attribute.getEntityAttributeId(), attribute);
    }
    // Mark for deletion attributes that were removed
    for (EntityAttribute attrib : existing.getAttributes()) {
      if (newAttribById.get(attrib.getEntityAttributeId()) == null) {
        attrib.setDateVoided(entity.getDateChanged());
        attrib.setUserVoidedBy(Context.getUserContext().getUser());
        entity.addAttribute(attrib);
      }
    }
  }
  /** Will export the entity passed in as the first parameter in the method into a file. */
  public String exportEntity(Entity entity, String filename) throws ApplicationException {
    if (entity == null) {
      return "";
    }

    String entityDefinition = exportEntity(entity.getEntityVersionId());
    try {

      // write to file
      File fileOut = new File(filename);
      BufferedWriter writer = null;

      writer = new BufferedWriter(new FileWriter(fileOut));

      writer.write(entityDefinition);
      writer.close();

      return entityDefinition;

    } catch (IOException e) {
      throw new RuntimeException("Unable to write new output file: " + filename);
    }
  }
  private void validateNameUniqueness(Entity entity) throws ApplicationException {
    @SuppressWarnings("rawtypes")
    List keys = entityDefinitionCache.getKeys();
    for (int i = 0; i < keys.size(); i++) {
      Object key = keys.get(i);
      Element elem = entityDefinitionCache.get(key);
      if (elem != null) {
        Entity item = (Entity) elem.getObjectValue();
        if (item.getDateVoided() != null) {
          continue;
        }

        if (entity.getName().equalsIgnoreCase(item.getName())
            && entity.getVersionId() == item.getVersionId()) {
          throw new ApplicationException(
              "Cannot add entity because another entity by the same name already exists.");
        }
      }
    }
  }
  @Override
  public LoggedLinkListWeb getLoggedLinks(LoggedLinkSearchCriteriaWeb search) throws Exception {
    authenticateCaller();
    try {
      AuditEventService auditEventService = Context.getAuditEventService();
      EntityDefinitionManagerService entityDefService = Context.getEntityDefinitionManagerService();
      RecordQueryService entityInstanceService = Context.getRecordQueryService();

      LoggedLinkListWeb loggedLinkList = new LoggedLinkListWeb();

      // entity model
      EntityWeb entityModel = search.getEntityModel();
      Entity entityDef = entityDefService.loadEntity(entityModel.getEntityVersionId());
      if (entityDef == null) {
        loggedLinkList.setTotalCount(0);
        loggedLinkList.setRecordPairs(new java.util.ArrayList<RecordLinkWeb>());
        return loggedLinkList;
      }

      //  total count
      int totalCount =
          auditEventService.getLoggedLinksCount(entityDef.getEntityVersionId(), search.getVector());
      if (totalCount == 0) {
        loggedLinkList.setTotalCount(0);
        loggedLinkList.setRecordPairs(new java.util.ArrayList<RecordLinkWeb>());
        return loggedLinkList;
      }

      // link logs
      List<LoggedLink> links =
          auditEventService.getLoggedLinks(
              entityDef.getEntityVersionId(),
              search.getVector(),
              search.getFirstResult(),
              search.getMaxResults());

      List<RecordLinkWeb> recordLinks = new java.util.ArrayList<RecordLinkWeb>();
      for (LoggedLink link : links) {

        Record leftRecord = entityInstanceService.loadRecordById(entityDef, link.getLeftRecordId());
        Record rightRecord =
            entityInstanceService.loadRecordById(entityDef, link.getRightRecordId());

        if (leftRecord != null && rightRecord != null) {
          RecordLinkWeb recordLinkWeb = new RecordLinkWeb();
          recordLinkWeb.setWeight(link.getWeight());
          recordLinkWeb.setVector(link.getVectorValue());
          recordLinkWeb.setDateCreated(link.getDateCreated());
          recordLinkWeb.setLeftRecord(ModelTransformer.mapToRecord(leftRecord, RecordWeb.class));
          recordLinkWeb.setRightRecord(ModelTransformer.mapToRecord(rightRecord, RecordWeb.class));

          if (link.getUserCreatedBy() != null) {
            UserWeb user =
                ModelTransformer.mapToUser(link.getUserCreatedBy(), UserWeb.class, false);
            recordLinkWeb.setUserCreatedBy(user);
          }

          recordLinks.add(recordLinkWeb);
        }
      }

      loggedLinkList.setTotalCount(totalCount);
      loggedLinkList.setRecordPairs(recordLinks);

      return loggedLinkList;
    } catch (Throwable t) {
      log.error("Failed to execute: " + t.getMessage(), t);
      throw new RuntimeException(t);
    }
  }
  /** Will import the entity definition specified in the relative filename of the parameter. */
  public void importEntity(String filename) throws ApplicationException {
    if (filename.isEmpty()) {
      return;
    }

    try {
      File file = new File(filename);
      log.debug("Loading file " + file.getAbsolutePath());
      if (!file.isFile() || !file.canRead()) {
        log.error("Input file is not available.");
        throw new RuntimeException("Input file " + filename + " is not readable.");
      }

      // Import from file
      JAXBContext jaxbContext = JAXBContext.newInstance(EntityModel.class);
      Unmarshaller unJaxbMarshaller = jaxbContext.createUnmarshaller();

      EntityModel entityModel = (EntityModel) unJaxbMarshaller.unmarshal(new FileInputStream(file));

      // convert EntityModel to Entity, EntityAttributeGroups, EntityAttributeValidations
      Entity entity =
          ConvertUtil.mapToEntityModel(entityModel, getEntityAttributeDatatypes(), Entity.class);

      // check existing entity
      List<Entity> entities = entityDefinitionDao.findEntitiesByName(entity.getName());
      for (Entity en : entities) {
        if (en.getVersionId().intValue() == entity.getVersionId().intValue()) {
          log.error("Entity definition already exists: " + entity.getName());
          throw new RuntimeException(
              "Entity definition in the file " + filename + " already exists.");
        }
      }

      // add entity
      Entity newEntity = addEntity(entity);

      // 2. add entity groups with attribute
      List<EntityAttributeGroup> groups =
          ConvertUtil.mapToEntityGroup(
              entityModel, newEntity, org.openhie.openempi.model.EntityAttributeGroup.class);
      for (EntityAttributeGroup group : groups) {
        addEntityAttributeGroup(group);
      }

      // 3. add entity attribute validations
      for (AttributeType attributeType : entityModel.getAttributes().getAttribute()) {
        List<EntityAttributeValidation> validations =
            ConvertUtil.mapToEntityValidations(
                attributeType,
                newEntity,
                org.openhie.openempi.model.EntityAttributeValidation.class);
        for (EntityAttributeValidation validation : validations) {
          addEntityAttributeValidation(validation);
        }
      }
      return;
    } catch (Exception e) {
      log.warn("Unable to Unmarshal xml to a EntityModel: " + e, e);
      throw new RuntimeException(e);
    }
  }