<commit_before>/*
 * Copyright 2015-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.dbflute.mail.send.embedded.receptionist;

import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.dbflute.Entity;
import org.dbflute.helper.filesystem.FileTextIO;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.mail.PostOffice;
import org.dbflute.mail.Postcard;
import org.dbflute.mail.Postcard.DirectBodyOption;
import org.dbflute.mail.send.SMailAddress;
import org.dbflute.mail.send.SMailReceptionist;
import org.dbflute.mail.send.exception.SMailFromAddressNotFoundException;
import org.dbflute.mail.send.exception.SMailIllegalStateException;
import org.dbflute.optional.OptionalThing;
import org.dbflute.util.DfCollectionUtil;
import org.dbflute.util.DfResourceUtil;
import org.dbflute.util.DfTypeUtil;
import org.dbflute.util.Srl;
import org.dbflute.util.Srl.ScopeInfo;

/**
 * @author jflute
 * @since 0.4.0 (2015/05/09 Saturday at nakameguro)
 */
public class SMailConventionReceptionist implements SMailReceptionist {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    public static final String META_DELIMITER = ">>>";
    public static final String COMMENT_BEGIN = "/*";
    public static final String COMMENT_END = "*/";
    public static final String TITLE_BEGIN = "[";
    public static final String TITLE_END = "]";
    public static final String SUBJECT_LABEL = "subject:";
    public static final String OPTION_LABEL = "option:";
    public static final String PLUS_HTML_OPTION = "+html";
    public static final String PROPDEF_PREFIX = "-- !!";
    public static final Set<String> optionSet;

    static {
        optionSet = Collections.unmodifiableSet(DfCollectionUtil.newLinkedHashSet(PLUS_HTML_OPTION));
    }

    public static final List<String> allowedPrefixList; // except first line (comment)

    static {
        allowedPrefixList = Arrays.asList(OPTION_LABEL, PROPDEF_PREFIX);
    }

    protected static final String LF = "\n";
    protected static final String CR = "\r";
    protected static final String CRLF = "\r\n";

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected String classpathBasePath; // used when from classpath, e.g. mail
    protected SMailDynamicTextAssist dynamicTextAssist; // e.g. from database, without text cache if specified
    protected SMailReceiverLocaleAssist receiverLocaleAssist; // e.g. null means no locale switch
    protected final Map<String, String> textCacheMap = new ConcurrentHashMap<String, String>();
    protected final FileTextIO textIO = createFileTextIO();
    protected final SMailConventionSecurity security = createConventionSecurity();

    protected FileTextIO createFileTextIO() {
        return new FileTextIO().encodeAsUTF8().removeUTF8Bom().replaceCrLfToLf();
    }

    protected SMailConventionSecurity createConventionSecurity() {
        return new SMailConventionSecurity();
    }

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    public SMailConventionReceptionist asClasspathBase(String classpathBasePath) {
        this.classpathBasePath = classpathBasePath;
        return this;
    }

    public SMailConventionReceptionist asDynamicText(SMailDynamicTextAssist dynamicTextAssist) {
        this.dynamicTextAssist = dynamicTextAssist;
        return this;
    }

    public SMailConventionReceptionist asReceiverLocale(SMailReceiverLocaleAssist receiverLocaleAssist) {
        this.receiverLocaleAssist = receiverLocaleAssist;
        return this;
    }

    // ===================================================================================
    //                                                                       Read BodyFile
    //                                                                       =============
    @Override
    public void accept(Postcard postcard) {
        readyPostcardFirst(postcard);
        checkPostcardFirst(postcard);
        if (postcard.isForcedlyDirect()) { // should ignore body file
            assertPlainBodyExistsForDirectBody(postcard);
            postcard.getBodyFile().ifPresent(bodyFile -> { // but wants logging
                officeManagedLogging(postcard, bodyFile, prepareReceiverLocale(postcard));
            });
            return;
        }
        postcard.getBodyFile().ifPresent(bodyFile -> {
            if (postcard.getHtmlBody().isPresent()) {
                String msg = "Cannot use direct HTML body when body file is specified: " + postcard;
                throw new SMailIllegalStateException(msg);
            }
            final boolean filesystem = postcard.isFromFilesystem();
            final OptionalThing<Locale> receiverLocale = prepareReceiverLocale(postcard);
            final OptionalThing<Object> dynamicData = prepareDynamicData(postcard, bodyFile, filesystem, receiverLocale);
            dynamicData.ifPresent(data -> acceptDynamicProperty(postcard, bodyFile, filesystem, receiverLocale, data));
            officeManagedLogging(postcard, bodyFile, receiverLocale);
            final String plainText = readText(postcard, bodyFile, false, filesystem, receiverLocale, dynamicData);
            analyzeBodyMeta(postcard, bodyFile, plainText);
            final DirectBodyOption option = postcard.useDirectBody(plainText);
            if (postcard.isAlsoHtmlFile()) {
                final String htmlFilePath = deriveHtmlFilePath(bodyFile);
                final String readHtml = readText(postcard, htmlFilePath, true, filesystem, receiverLocale, dynamicData);
                verifyMailHtmlTemplateTextFormat(htmlFilePath, readHtml);
                option.alsoDirectHtml(readHtml);
            }
            // no check about unneeded HTML template file because of runtime performance
            // DBFlute generator checks it instead
        }).orElse(() -> { /* direct body, check only here */
            assertPlainBodyExistsForDirectBody(postcard);
        });
        if (!postcard.getFrom().isPresent()) { // is moved from office check of postcard
            throwMailFromAddressNotFoundException(postcard);
        }
    }

    // -----------------------------------------------------
    //                                           Ready First
    //                                           -----------
    protected void readyPostcardFirst(Postcard postcard) { // may be overridden
    }
<commit_msg>small comment<commit_after>/*
 * Copyright 2015-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.dbflute.mail.send.embedded.receptionist;

import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.dbflute.Entity;
import org.dbflute.helper.filesystem.FileTextIO;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.mail.PostOffice;
import org.dbflute.mail.Postcard;
import org.dbflute.mail.Postcard.DirectBodyOption;
import org.dbflute.mail.send.SMailAddress;
import org.dbflute.mail.send.SMailReceptionist;
import org.dbflute.mail.send.exception.SMailFromAddressNotFoundException;
import org.dbflute.mail.send.exception.SMailIllegalStateException;
import org.dbflute.optional.OptionalThing;
import org.dbflute.util.DfCollectionUtil;
import org.dbflute.util.DfResourceUtil;
import org.dbflute.util.DfTypeUtil;
import org.dbflute.util.Srl;
import org.dbflute.util.Srl.ScopeInfo;

/**
 * @author jflute
 * @since 0.4.0 (2015/05/09 Saturday at nakameguro)
 */
public class SMailConventionReceptionist implements SMailReceptionist {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    public static final String META_DELIMITER = ">>>";
    public static final String COMMENT_BEGIN = "/*";
    public static final String COMMENT_END = "*/";
    public static final String TITLE_BEGIN = "[";
    public static final String TITLE_END = "]";
    public static final String SUBJECT_LABEL = "subject:";
    public static final String OPTION_LABEL = "option:";
    public static final String PLUS_HTML_OPTION = "+html";
    public static final String PROPDEF_PREFIX = "-- !!";
    public static final Set<String> optionSet;

    static {
        optionSet = Collections.unmodifiableSet(DfCollectionUtil.newLinkedHashSet(PLUS_HTML_OPTION));
    }

    public static final List<String> allowedPrefixList; // except first line (comment)

    static {
        allowedPrefixList = Arrays.asList(OPTION_LABEL, PROPDEF_PREFIX);
    }

    protected static final String LF = "\n";
    protected static final String CR = "\r";
    protected static final String CRLF = "\r\n";

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected String classpathBasePath; // used when from classpath, e.g. mail
    protected SMailDynamicTextAssist dynamicTextAssist; // e.g. from database, without text cache if specified
    protected SMailReceiverLocaleAssist receiverLocaleAssist; // e.g. null means no locale switch
    protected final Map<String, String> textCacheMap = new ConcurrentHashMap<String, String>();
    protected final FileTextIO textIO = createFileTextIO();
    protected final SMailConventionSecurity security = createConventionSecurity();

    protected FileTextIO createFileTextIO() {
        return new FileTextIO().encodeAsUTF8().removeUTF8Bom().replaceCrLfToLf();
    }

    protected SMailConventionSecurity createConventionSecurity() {
        return new SMailConventionSecurity();
    }

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    public SMailConventionReceptionist asClasspathBase(String classpathBasePath) {
        this.classpathBasePath = classpathBasePath;
        return this;
    }

    public SMailConventionReceptionist asDynamicText(SMailDynamicTextAssist dynamicTextAssist) {
        this.dynamicTextAssist = dynamicTextAssist;
        return this;
    }

    public SMailConventionReceptionist asReceiverLocale(SMailReceiverLocaleAssist receiverLocaleAssist) {
        this.receiverLocaleAssist = receiverLocaleAssist;
        return this;
    }

    // ===================================================================================
    //                                                                       Read BodyFile
    //                                                                       =============
    @Override
    public void accept(Postcard postcard) {
        readyPostcardFirst(postcard);
        checkPostcardFirst(postcard);
        if (postcard.isForcedlyDirect()) { // should ignore body file
            assertPlainBodyExistsForDirectBody(postcard);
            postcard.getBodyFile().ifPresent(bodyFile -> { // but wants logging
                officeManagedLogging(postcard, bodyFile, prepareReceiverLocale(postcard));
            });
            return;
        }
        postcard.getBodyFile().ifPresent(bodyFile -> {
            if (postcard.getHtmlBody().isPresent()) {
                String msg = "Cannot use direct HTML body when body file is specified: " + postcard;
                throw new SMailIllegalStateException(msg);
            }
            final boolean filesystem = postcard.isFromFilesystem();
            final OptionalThing<Locale> receiverLocale = prepareReceiverLocale(postcard);
            final OptionalThing<Object> dynamicData = prepareDynamicData(postcard, bodyFile, filesystem, receiverLocale);
            dynamicData.ifPresent(data -> acceptDynamicProperty(postcard, bodyFile, filesystem, receiverLocale, data));
            officeManagedLogging(postcard, bodyFile, receiverLocale);
            final String plainText = readText(postcard, bodyFile, false, filesystem, receiverLocale, dynamicData);
            analyzeBodyMeta(postcard, bodyFile, plainText);
            final DirectBodyOption option = postcard.useDirectBody(plainText);
            if (postcard.isAlsoHtmlFile()) {
                final String htmlFilePath = deriveHtmlFilePath(bodyFile);
                final String readHtml = readText(postcard, htmlFilePath, true, filesystem, receiverLocale, dynamicData);
                verifyMailHtmlTemplateTextFormat(htmlFilePath, readHtml);
                option.alsoDirectHtml(readHtml);
            }
            // no check about unneeded HTML template file because of runtime performance
            // DBFlute generator checks it instead
        }).orElse(() -> { /* direct body, check only here */
            assertPlainBodyExistsForDirectBody(postcard);
        });
        if (!postcard.getFrom().isPresent()) { // is moved from office check of postcard for dynamic property
            throwMailFromAddressNotFoundException(postcard);
        }
    }

    // -----------------------------------------------------
    //                                           Ready First
    //                                           -----------
    protected void readyPostcardFirst(Postcard postcard) { // may be overridden
    }

{'fraction_non_alphanumeric': 0.13059343191857115, 'fraction_numerical': 0.003200819409768901, 'mean_word_length': 2.4236248082401928, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 56, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4337292', 'n_tokens_mistral': 3731, 'n_tokens_neox': 3598, 'n_words': 944}