public FieldGroupFieldInstance fieldGroupFieldInstanceAdded(
        @Optional DomainEvent event, Field fieldGroup, String id, Field fieldGroupField) {
      EntityBuilder<FieldGroupFieldInstance> builder =
          module
              .unitOfWorkFactory()
              .currentUnitOfWork()
              .newEntityBuilder(FieldGroupFieldInstance.class, id);
      builder.instance().addFieldGroup(fieldGroup);
      builder.instance().addFieldGroupField(fieldGroupField);
      FieldGroupFieldInstance field = builder.newInstance();

      data.groupFields().add(field);
      return field;
    }
 public void addFieldGroupFields(Field field) {
   FieldGroupFieldValue value =
       (FieldGroupFieldValue) ((FieldValueDefinition.Data) field).fieldValue().get();
   // find field group definition, and recurse for each field
   Fields.Data fields =
       module
           .unitOfWorkFactory()
           .currentUnitOfWork()
           .get(Fields.Data.class, value.fieldGroup().get().identity());
   for (Field groupField : fields.fields()) {
     Field createdField =
         fieldGroupFieldsAdded(null, field, idGen.generate(Identity.class), groupField);
     createdField.changeDescription(groupField.getDescription());
     fieldGroupFieldInstanceAdded(null, field, idGen.generate(Identity.class), createdField);
   }
 }
    /**
     * Try to determine what address from the to address list should be used as main TO address for
     * the different EmailReceiver's. In case the references header is null we try to find a
     * matching email access point.
     *
     * @param recipients The recipients from the TO address list
     * @param references The references header
     * @return A hopefully valid email address as a string
     */
    private String toaddress(final Address[] recipients, String references) {
      String result = "";
      // No recipients found return n/a
      if (recipients == null || recipients.length == 0) return "n/a";

      if (!hasStreamflowReference(references)) {
        Organizations.Data organizations =
            module
                .unitOfWorkFactory()
                .currentUnitOfWork()
                .get(Organizations.Data.class, OrganizationsEntity.ORGANIZATIONS_ID);
        EmailAccessPoints.Data emailAccessPoints =
            (EmailAccessPoints.Data) organizations.organization().get();

        Iterable<EmailAccessPoint> possibleAccesspoints =
            Iterables.filter(
                new Specification<EmailAccessPoint>() {
                  public boolean satisfiedBy(final EmailAccessPoint accessPoint) {
                    return Iterables.matchesAny(
                        new Specification<Address>() {
                          public boolean satisfiedBy(Address address) {
                            return ((InternetAddress) address)
                                .getAddress()
                                .equalsIgnoreCase(accessPoint.getDescription());
                          }
                        },
                        Arrays.asList(recipients));
                  }
                },
                emailAccessPoints.emailAccessPoints().toList());

        if (Iterables.count(possibleAccesspoints) > 0)
          result = Iterables.first(possibleAccesspoints).getDescription();
        else result = ((InternetAddress) recipients[0]).getAddress();

      } else {
        result = ((InternetAddress) recipients[0]).getAddress();
      }

      return Strings.empty(result) ? "n/a" : result.toLowerCase();
    }
    public Field fieldGroupFieldsAdded(
        @Optional DomainEvent event, Field fieldGroup, String id, Field fieldGroupField) {

      FieldValueDefinition.Data definition = (FieldValueDefinition.Data) fieldGroupField;

      EntityBuilder<Field> fieldBuilder =
          module.unitOfWorkFactory().currentUnitOfWork().newEntityBuilder(Field.class, id);
      fieldBuilder.instanceFor(Mandatory.Data.class).mandatory().set(fieldGroupField.isMandatory());
      fieldBuilder.instanceFor(Notable.Data.class).note().set(fieldGroupField.getNote());
      fieldBuilder
          .instanceFor(Describable.Data.class)
          .description()
          .set(fieldGroupField.getDescription());
      fieldBuilder
          .instanceFor(Datatype.Data.class)
          .datatype()
          .set(((Datatype.Data) fieldGroupField).datatype().get());
      fieldBuilder
          .instanceFor(Statistical.Data.class)
          .statistical()
          .set(((Statistical.Data) fieldGroupField).statistical().get());

      FieldValue fieldValue = definition.fieldValue().get();
      fieldBuilder.instanceFor(FieldValueDefinition.Data.class).fieldValue().set(fieldValue);

      String fieldId =
          Classes.interfacesOf(fieldValue.getClass()).iterator().next().getSimpleName();
      fieldId =
          fieldGroup.getDescription()
              + "_"
              + fieldId.substring(0, fieldId.length() - "FieldValue".length());
      fieldId += data.groupFields().count() + 1;
      fieldBuilder.instanceFor(FieldId.Data.class).fieldId().set(fieldId);

      Field createdFieldGroupField = fieldBuilder.newInstance();

      return createdFieldGroupField;
    }
    public void run() {
      Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

      if (!circuitBreaker.isOn()) return; // Don't try - circuit breaker is off

      boolean expunge = config.configuration().deleteMailOnInboxClose().get();
      if (config.configuration().debug().get()) {
        logger.info("Checking email");
        logger.info("Delete mail on close - " + expunge);
      }

      Session session = javax.mail.Session.getInstance(props, authenticator);
      session.setDebug(config.configuration().debug().get());

      Usecase usecase = newUsecase("Receive Mail");
      UnitOfWork uow = null;
      Store store = null;
      Folder inbox = null;
      Folder archive = null;
      boolean archiveExists = false;
      List<Message> copyToArchive = new ArrayList<Message>();
      MimeMessage internalMessage = null;

      try {
        store = session.getStore(url);
        store.connect();

        inbox = store.getFolder("INBOX");
        inbox.open(Folder.READ_WRITE);

        javax.mail.Message[] messages = inbox.getMessages();
        FetchProfile fp = new FetchProfile();
        //            fp.add( "In-Reply-To" );
        inbox.fetch(messages, fp);

        // check if the archive folder is configured and exists
        if (!Strings.empty(config.configuration().archiveFolder().get())
            && config.configuration().protocol().get().startsWith("imap")) {
          archive = store.getFolder(config.configuration().archiveFolder().get());

          // if not exists - create
          if (!archive.exists()) {
            archive.create(Folder.HOLDS_MESSAGES);
            archiveExists = true;
          } else {
            archiveExists = true;
          }

          archive.open(Folder.READ_WRITE);
        }

        for (javax.mail.Message message : messages) {
          int tries = 0;
          while (tries < 3) {
            uow = module.unitOfWorkFactory().newUnitOfWork(usecase);

            ValueBuilder<EmailValue> builder =
                module.valueBuilderFactory().newValueBuilder(EmailValue.class);

            try {
              // Force a complete fetch of the message by cloning it to a internal MimeMessage
              // to avoid "javax.mail.MessagingException: Unable to load BODYSTRUCTURE" problems
              // f.ex. experienced if the message contains a windows .eml file as attachment!

              // Beware that all flag and folder operations have to be made on the original message
              // and not on the internal one!!
              internalMessage = new MimeMessage((MimeMessage) message);

              Object content = internalMessage.getContent();

              // Get email fields
              builder
                  .prototype()
                  .from()
                  .set(((InternetAddress) internalMessage.getFrom()[0]).getAddress());
              builder
                  .prototype()
                  .fromName()
                  .set(((InternetAddress) internalMessage.getFrom()[0]).getPersonal());
              builder
                  .prototype()
                  .subject()
                  .set(internalMessage.getSubject() == null ? "" : internalMessage.getSubject());

              // Get headers
              for (Header header :
                  Iterables.iterable((Enumeration<Header>) internalMessage.getAllHeaders())) {
                builder.prototype().headers().get().put(header.getName(), header.getValue());
              }

              // Get all recipients in order - TO, CC, BCC
              // and provide it to the toaddress method to pick the first possible valid adress
              builder
                  .prototype()
                  .to()
                  .set(
                      toaddress(
                          internalMessage.getAllRecipients(),
                          builder.prototype().headers().get().get("References")));

              builder.prototype().messageId().set(internalMessage.getHeader("Message-ID")[0]);

              // Get body and attachments
              String body = "";
              // set content initially so it never can become null
              builder.prototype().content().set(body);

              if (content instanceof String) {
                body = content.toString();
                builder.prototype().content().set(body);
                String contentTypeString = cleanContentType(internalMessage.getContentType());
                builder.prototype().contentType().set(contentTypeString);
                if (Translator.HTML.equalsIgnoreCase(contentTypeString)) {
                  builder.prototype().contentHtml().set(body);
                }

              } else if (content instanceof Multipart) {
                handleMultipart((Multipart) content, internalMessage, builder);
              } else if (content instanceof InputStream) {
                content = new MimeMessage(session, (InputStream) content).getContent();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                Inputs.byteBuffer((InputStream) content, 4096).transferTo(Outputs.byteBuffer(baos));

                String data = new String(baos.toByteArray(), "UTF-8");
                // Unknown content type - abort
                // and create failure case
                String subj = "Unkonwn content type: " + internalMessage.getSubject();
                builder
                    .prototype()
                    .subject()
                    .set(subj.length() > 50 ? subj.substring(0, 50) : subj);
                builder.prototype().content().set(body);
                builder.prototype().contentType().set(internalMessage.getContentType());
                systemDefaults.createCaseOnEmailFailure(builder.newInstance());
                copyToArchive.add(message);
                if (expunge) message.setFlag(Flags.Flag.DELETED, true);

                uow.discard();
                tries = 3;
                continue;
              } else {
                // Unknown content type - abort
                // and create failure case
                String subj = "Unkonwn content type: " + internalMessage.getSubject();
                builder
                    .prototype()
                    .subject()
                    .set(subj.length() > 50 ? subj.substring(0, 50) : subj);
                builder.prototype().content().set(body);
                builder.prototype().contentType().set(internalMessage.getContentType());
                systemDefaults.createCaseOnEmailFailure(builder.newInstance());
                copyToArchive.add(message);
                if (expunge) message.setFlag(Flags.Flag.DELETED, true);

                uow.discard();
                logger.error(
                    "Could not parse emails: unknown content type " + content.getClass().getName());
                tries = 3;
                continue;
              }

              // make sure mail content fit's into statistic database - truncate on 65.500
              // characters.
              if (builder.prototype().content().get().length() > 65000) {
                builder
                    .prototype()
                    .content()
                    .set(builder.prototype().content().get().substring(0, 65000));
              }

              // try to reveal if it is a smpt error we are looking at
              // X-Failed-Recipients is returned by Gmail
              // X-FC-MachineGenerated is returned by FirstClass
              // Exchange is following RFC 6522 -  The Multipart/Report Media Type for
              // the Reporting of Mail System Administrative Messages
              boolean isSmtpErrorReport =
                  !Strings.empty(builder.prototype().headers().get().get("X-Failed-Recipients"))
                      || (!Strings.empty(
                              builder.prototype().headers().get().get("X-FC-MachineGenerated"))
                          && "true"
                              .equals(
                                  builder.prototype().headers().get().get("X-FC-MachineGenerated")))
                      || !Strings.empty(
                          new ContentType(builder.prototype().headers().get().get("Content-Type"))
                              .getParameter("report-type"));

              if (isSmtpErrorReport) {
                // This is a mail bounce due to SMTP error - create support case.
                String subj = "Undeliverable mail: " + builder.prototype().subject().get();

                builder
                    .prototype()
                    .subject()
                    .set(subj.length() > 50 ? subj.substring(0, 50) : subj);
                systemDefaults.createCaseOnEmailFailure(builder.newInstance());
                copyToArchive.add(message);
                if (expunge) message.setFlag(Flags.Flag.DELETED, true);

                uow.discard();
                logger.error("Received a mail bounce reply: " + body);
                tries = 3;
                continue;
              }

              if (builder.prototype().to().get().equals("n/a")) {
                // This is a mail has no to address - create support case.

                String subj = "No TO address: " + builder.prototype().subject().get();

                builder
                    .prototype()
                    .subject()
                    .set(subj.length() > 50 ? subj.substring(0, 50) : subj);
                systemDefaults.createCaseOnEmailFailure(builder.newInstance());
                copyToArchive.add(message);
                if (expunge) message.setFlag(Flags.Flag.DELETED, true);

                uow.discard();
                logger.error("Received a mail without TO address: " + body);
                tries = 3;
                continue;
              }

              mailReceiver.receivedEmail(null, builder.newInstance());

              try {
                logger.debug("This is try " + tries);
                uow.complete();
                tries = 3;
              } catch (ConcurrentEntityModificationException ceme) {
                if (tries < 2) {
                  logger.debug("Encountered ConcurrentEntityModificationException - try again ");
                  // discard uow and try again
                  uow.discard();
                  tries++;
                  continue;

                } else {
                  logger.debug("Rethrowing ConcurrentEntityModification.Exception");
                  tries++;
                  throw ceme;
                }
              }

              copyToArchive.add(message);
              // remove mail on success if expunge is true
              if (expunge) message.setFlag(Flags.Flag.DELETED, true);

            } catch (Throwable e) {
              String subj = "Unknown error: " + internalMessage.getSubject();
              builder.prototype().subject().set(subj.length() > 50 ? subj.substring(0, 50) : subj);

              StringBuilder content = new StringBuilder();
              content.append("Error Message: " + e.getMessage());
              content.append("\n\rStackTrace:\n\r");
              for (StackTraceElement trace : Arrays.asList(e.getStackTrace())) {
                content.append(trace.toString() + "\n\r");
              }

              builder.prototype().content().set(content.toString());
              // since we create the content of the message our self it's ok to set content type
              // always to text/plain
              builder.prototype().contentType().set("text/plain");

              // Make sure to address has some value before vi create a case!!
              if (builder.prototype().to().get() == null) {
                builder.prototype().to().set("n/a");
              }
              systemDefaults.createCaseOnEmailFailure(builder.newInstance());
              copyToArchive.add(message);
              if (expunge) message.setFlag(Flags.Flag.DELETED, true);

              uow.discard();
              logger.error("Could not parse emails", e);
              tries = 3;
            }
          }
        }

        // copy message to archive if archive exists
        if (archiveExists) {
          inbox.copyMessages(copyToArchive.toArray(new Message[0]), archive);
          archive.close(false);
        }

        inbox.close(config.configuration().deleteMailOnInboxClose().get());

        store.close();

        if (config.configuration().debug().get()) {
          logger.info("Checked email");
        }

        circuitBreaker.success();
      } catch (Throwable e) {
        logger.error("Error in mail receiver: ", e);
        circuitBreaker.throwable(e);

        try {
          if (inbox != null && inbox.isOpen()) inbox.close(false);

          if (store != null && store.isConnected()) store.close();
        } catch (Throwable e1) {
          logger.error("Could not close inbox", e1);
        }
      }
    }
    public void activate() throws Exception {
      circuitBreaker = descriptor.metaInfo(CircuitBreaker.class);

      logger = LoggerFactory.getLogger(ReceiveMailService.class);

      if (config.configuration().enabled().get()) {
        UnitOfWork uow =
            module
                .unitOfWorkFactory()
                .newUnitOfWork(newUsecase("Create Streamflow support structure"));
        RoleMap.newCurrentRoleMap();
        RoleMap.current().set(uow.get(UserAuthentication.class, UserEntity.ADMINISTRATOR_USERNAME));
        RoleMap.current().set(new UserPrincipal(UserEntity.ADMINISTRATOR_USERNAME));

        Organizations.Data orgs =
            uow.get(OrganizationsEntity.class, OrganizationsEntity.ORGANIZATIONS_ID);
        OrganizationEntity org = (OrganizationEntity) orgs.organization().get();
        // check for the existance of support structure for mails that cannot be parsed
        RoleMap.current().set(org.getAdministratorRole());

        OrganizationalUnit ou = null;
        Project project = null;
        CaseType caseType = null;

        try {
          try {
            ou =
                org.getOrganizationalUnitByName(
                    systemDefaults.config().configuration().supportOrganizationName().get());
          } catch (IllegalArgumentException iae) {
            ou =
                org.createOrganizationalUnit(
                    systemDefaults.config().configuration().supportOrganizationName().get());
          }

          try {
            project =
                ou.getProjectByName(
                    systemDefaults.config().configuration().supportProjectName().get());
          } catch (IllegalArgumentException iae) {
            project =
                ou.createProject(
                    systemDefaults.config().configuration().supportProjectName().get());
          }

          try {
            caseType =
                project.getCaseTypeByName(
                    systemDefaults
                        .config()
                        .configuration()
                        .supportCaseTypeForIncomingEmailName()
                        .get());
          } catch (IllegalArgumentException iae) {
            caseType =
                ou.createCaseType(
                    systemDefaults
                        .config()
                        .configuration()
                        .supportCaseTypeForIncomingEmailName()
                        .get());
            project.addSelectedCaseType(caseType);
            project.addMember(RoleMap.current().get(Member.class));
          }
        } finally {
          uow.complete();
          RoleMap.clearCurrentRoleMap();
        }

        // Authenticator
        authenticator =
            new javax.mail.Authenticator() {
              protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                    config.configuration().user().get(), config.configuration().password().get());
              }
            };

        props = new Properties();

        String protocol = config.configuration().protocol().get();
        props.put("mail." + protocol + ".host", config.configuration().host().get());
        props.put("mail.transport.protocol", protocol);
        props.put("mail." + protocol + ".auth", "true");
        props.put("mail." + protocol + ".port", config.configuration().port().get());

        if (config.configuration().useSSL().get()) {

          props.setProperty(
              "mail." + protocol + ".socketFactory.class", "javax.net.ssl.SSLSocketFactory");
          props.setProperty("mail." + protocol + ".socketFactory.fallback", "false");
          props.setProperty(
              "mail." + protocol + ".socketFactory.port", "" + config.configuration().port().get());
        }

        url =
            new URLName(
                protocol,
                config.configuration().host().get(),
                config.configuration().port().get(),
                "",
                config.configuration().user().get(),
                config.configuration().password().get());

        circuitBreaker.addVetoableChangeListener(this);
        circuitBreaker.turnOn();

        long sleep = config.configuration().sleepPeriod().get();
        logger.info(
            "Starting scheduled mail receiver thread. Checking every: "
                + (sleep == 0 ? 10 : sleep)
                + " min");
        receiverExecutor =
            Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("ReceiveMail"));
        receiverExecutor.scheduleWithFixedDelay(
            this, 0, (sleep == 0 ? 10 : sleep), TimeUnit.MINUTES);
      }
    }