<commit_before>/*
 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * Contributors:
 *     <a href="mailto:<EMAIL>">Tiry</a>
 *     <a href="mailto:<EMAIL>">Guillaume</a>
 */

package org.nuxeo.ecm.platform.ui.select2;

import java.io.BufferedOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonGenerator;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.FacesLifecycle;
import org.nuxeo.ecm.automation.AutomationService;
import org.nuxeo.ecm.automation.InvalidChainException;
import org.nuxeo.ecm.automation.OperationContext;
import org.nuxeo.ecm.automation.OperationException;
import org.nuxeo.ecm.automation.jaxrs.io.JsonHelper;
import org.nuxeo.ecm.automation.jaxrs.io.documents.JsonDocumentWriter;
import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.CoreInstance;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.DocumentRef;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.NuxeoGroup;
import org.nuxeo.ecm.core.api.NuxeoPrincipal;
import org.nuxeo.ecm.core.api.PathRef;
import org.nuxeo.ecm.core.api.repository.Repository;
import org.nuxeo.ecm.core.api.repository.RepositoryManager;
import org.nuxeo.ecm.core.schema.SchemaManager;
import org.nuxeo.ecm.core.schema.types.Field;
import org.nuxeo.ecm.core.schema.types.QName;
import org.nuxeo.ecm.core.schema.types.Schema;
import org.nuxeo.ecm.directory.Directory;
import org.nuxeo.ecm.directory.DirectoryException;
import org.nuxeo.ecm.directory.Session;
import org.nuxeo.ecm.directory.api.DirectoryService;
import org.nuxeo.ecm.platform.forms.layout.api.Widget;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore;
import org.nuxeo.ecm.platform.ui.select2.automation.SuggestUserEntries;
import org.nuxeo.ecm.platform.ui.select2.common.Select2Common;
import org.nuxeo.ecm.platform.url.DocumentViewImpl;
import org.nuxeo.ecm.platform.url.codec.DocumentIdCodec;
import org.nuxeo.ecm.platform.usermanager.UserManager;
import org.nuxeo.runtime.api.Framework;

/**
 * Initialization for Select2.
 *
 * @since 5.7.3
 */
@Name("select2Actions")
@Scope(ScopeType.EVENT)
public class Select2ActionsBean implements Serializable {

    private static final long serialVersionUID = 1L;

    @SuppressWarnings("unused")
    private static final Log log = LogFactory.getLog(Select2ActionsBean.class);

    protected static final String SELECT2_RESOURCES_MARKER = "SELECT2_RESOURCES_MARKER";

    private static List<String> formatList(JSONArray array) {
        List<String> result = new ArrayList<String>();
        if (array != null) {
            for (int i = 0; i < array.size(); i++) {
                result.add(array.getJSONObject(i).getString(Select2Common.LABEL));
            }
        }
        return result;
    }

    @In(create = true)
    protected Map<String, String> messages;

    @In(create = true, required = false)
    protected transient CoreSession documentManager;

    protected transient CoreSession dedicatedSession = null;

    @Destroy
    public void destroy() {
        if (dedicatedSession != null) {
            CoreInstance.getInstance().close(dedicatedSession);
        }
    }

    /**
     * Encode widget properties and parameters that Select2 pick them up in a
     * hidden input.
     *
     * @param widget the widget
     * @return encoded
     * @throws Exception
     *
     * @since 5.7.3
     */
    public String encodeParameters(final Widget widget) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedOutputStream out = new BufferedOutputStream(baos);

        JsonGenerator jg = JsonHelper.createJsonGenerator(out);
        jg.writeStartObject();

        // multiple is not in properties and we must add it because Select2
        // needs to know.
        jg.writeStringField("multiple", "" + isMultiSelection(widget));

        final boolean isTranslated = widget.isTranslated();

        // The operation might need to know if we translate the labels or not.
        jg.writeStringField("translateLabels", "" + isTranslated);

        Map<String, Serializable> propertySet = widget.getProperties();
        boolean hasPlaceholder = false, hasSuggestionFormatter = false, hasSelectionFormatter = false, hasAjaxReRender = false;

        for (Entry<String, Serializable> entry : propertySet.entrySet()) {

            String value = entry.getValue().toString();

            if (entry.getKey().equals(Select2Common.PLACEHOLDER)) {
                hasPlaceholder = true;
                // placeholder can be translated
                if (isTranslated) {
                    value = messages.get(entry.getValue().toString());
                }
            } else if (entry.getKey().equals(Select2Common.SUGGESTION_FORMATTER)) {
                hasSuggestionFormatter = true;
            } else if (entry.getKey().equals(Select2Common.SELECTION_FORMATTER)) {
                hasSelectionFormatter = true;
            } else if (entry.getKey().equals(Select2Common.AJAX_RERENDER)) {
                hasAjaxReRender = true;
            }

            jg.writeStringField(entry.getKey(), value);

        }

        if (!hasPlaceholder) {
            // No placeholder provider and Select2 requires one to enable the
            // reset button.
            jg.writeStringField(Select2Common.PLACEHOLDER,
                    messages.get("label.vocabulary.selectValue"));
        }

        // Had default selection and suggestion formatter if needed.
        if (widget.getType().startsWith(Select2Common.USER_SUGGESTION_SELECT2)) {
            jg.writeStringField("operationId", SuggestUserEntries.ID);
            if (!hasSuggestionFormatter) {
                jg.writeStringField(Select2Common.SUGGESTION_FORMATTER,
                        Select2Common.USER_DEFAULT_SUGGESTION_FORMATTER);
            }
            if (!hasSelectionFormatter) {
                jg.writeStringField(Select2Common.SELECTION_FORMATTER,
                        Select2Common.USER_DEFAULT_SELECTION_FORMATTER);
            }
        } else if (widget.getType().startsWith(Select2Common.SUGGESTION_SELECT2)) {
            if (!hasSuggestionFormatter) {
                jg.writeStringField(Select2Common.SUGGESTION_FORMATTER,
                        Select2Common.DOC_DEFAULT_SUGGESTION_FORMATTER);
            }
            if (!hasSelectionFormatter) {
                jg.writeStringField(Select2Common.SELECTION_FORMATTER,
                        Select2Common.DOC_DEFAULT_SELECTION_FORMATTER);
            }
        } else if (widget.getType().startsWith(
                Select2Common.DIR_SUGGESTION_SELECT2)) {
            if (!hasSuggestionFormatter) {
                jg.writeStringField(Select2Common.SUGGESTION_FORMATTER,
                        Select2Common.DIR_DEFAULT_SUGGESTION_FORMATTER);
            }
            if (!hasSelectionFormatter) {
                jg.writeStringField(Select2Common.SELECTION_FORMATTER,
                        Select2Common.DIR_DEFAULT_SELECTION_FORMATTER);
            }
        }

        // Are we writing or reading
        boolean readonly = !widget.getMode().equals("edit")
                && !widget.getMode().equals("create");
        jg.writeStringField(Select2Common.READ_ONLY_PARAM,
                Boolean.toString(readonly));
        if (hasAjaxReRender) {
            jg.writeStringField(Select2Common.RERENDER_JS_FUNCTION_NAME,
                    widget.getId() + "_reRender");
        }

        jg.writeEndObject();
        jg.flush();
        out.flush();
        return new String(baos.toByteArray(), "UTF-8");
    }

    protected LayoutStore getLayoutStore() {
        LayoutStore layoutStore = null;
        try {
            layoutStore = Framework.getLocalService(LayoutStore.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (layoutStore == null) {
            throw new RuntimeException("Missing service for LayoutStore");
        }
        return layoutStore;
    }

    protected JSONArray getMultipleDirectoryEntries(final Object value,
            final String directoryName, final boolean translateLabels,
            String keySeparator, final boolean dbl10n,
            final String labelFieldName) {
        JSONArray result = new JSONArray();
        if (value == null) {
            return result;
        }

        List<String> storedRefs = new ArrayList<>();
        if (value instanceof List) {
            for (Object v : (List) value) {
                storedRefs.add(v.toString());
            }
        } else if (value instanceof Object[]) {
            for (Object v : (Object[]) value) {
                storedRefs.add(v.toString());
            }
        }

        DirectoryService directoryService = Framework.getLocalService(DirectoryService.class);
        Directory directory = null;
        Session session = null;
        try {
            directory = directoryService.getDirectory(directoryName);
            if (directory == null) {
                log.error("Could not find directory with name " + directoryName);
                return result;
            }
            session = directory.getSession();
            String schemaName = directory.getSchema();
            SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
            Schema schema = schemaManager.getSchema(schemaName);
            final Locale locale = org.jboss.seam.core.Locale.instance();
            final String label = Select2Common.getLabelFieldName(schema,
                    dbl10n, labelFieldName, locale.getLanguage());

            for (String ref : storedRefs) {
                JSONObject obj = resolveDirectoryEntry(ref, keySeparator,
                        session, schema, label, translateLabels, dbl10n);
                if (obj != null) {
                    result.add(obj);
                }
            }
            return result;
        } catch (DirectoryException de) {
            log.error("An error occured while obtaining directory "
                    + directoryName, de);
            return result;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (ClientException ce) {
                log.error("Could not close directory session", ce);
            }
        }

    }

    protected JSONArray getMultipleUserReference(final Object value,
            final boolean prefixed) {
        if (value == null) {
            return null;
        }
        JSONArray result = new JSONArray();
        List<String> storedRefs = new ArrayList<>();
        if (value instanceof List) {
            for (Object v : (List) value) {
                storedRefs.add(v.toString());
            }
        } else if (value instanceof Object[]) {
            for (Object v : (Object[]) value) {
                storedRefs.add(v.toString());
            }
        }

        for (String ref : storedRefs) {
            JSONObject resolved = getSingleUserReference(ref, prefixed);
            if (resolved != null && !resolved.isEmpty()) {
                result.add(resolved);
            }
        }
        return result;
    }

    protected CoreSession getRepositorySession(final String repoName)
            throws ClientException {

        RepositoryManager rm = Framework.getLocalService(RepositoryManager.class);
        Repository repository = null;
        if (repoName == null || repoName.isEmpty()) {
            repository = rm.getDefaultRepository();
        } else {
            repository = rm.getRepository(repoName);
            if (repository == null) {
                log.error("Unable to resolve repository " + repoName);
                return null;
            }
        }

        if (documentManager != null
                && documentManager.getRepositoryName().equals(
                        repository.getName())) {
            return documentManager;
        }

        try {
            dedicatedSession = repository.open();
            return dedicatedSession;
        } catch (Exception e) {
            throw new ClientException(e);
        }
    }

    protected JSONObject getSingleDirectoryEntry(final String storedReference,
            final String directoryName, final boolean translateLabels,
            String keySeparator, final boolean dbl10n,
            final String labelFieldName) {

        if (storedReference == null || storedReference.isEmpty()) {
            return null;
        }

        DirectoryService directoryService = Framework.getLocalService(DirectoryService.class);
        Directory directory = null;
        Session session = null;
        try {
            directory = directoryService.getDirectory(directoryName);
            if (directory == null) {
                log.error("Could not find directory with name " + directoryName);
                return null;
            }
            session = directory.getSession();
            String schemaName = directory.getSchema();
            SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
            Schema schema = schemaManager.getSchema(schemaName);

            final Locale locale = org.jboss.seam.core.Locale.instance();
            final String label = Select2Common.getLabelFieldName(schema,
                    dbl10n, labelFieldName, locale.getLanguage());

            JSONObject obj = resolveDirectoryEntry(storedReference,
                    keySeparator, session, schema, label, translateLabels,
                    dbl10n);

            return obj;
        } catch (DirectoryException de) {
            log.error("An error occured while obtaining directory "
                    + directoryName, de);
            return null;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (ClientException ce) {
                log.error("Could not close directory session", ce);
            }
        }

    }

    protected JSONObject getSingleUserReference(final String storedReference,
            final boolean prefixed) {
        UserManager userManager = Framework.getLocalService(UserManager.class);
        SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
        JSONObject obj = new JSONObject();
        if (storedReference == null || storedReference.isEmpty()) {
            return null;
        }
        try {
            DocumentModel user = null;
            DocumentModel group = null;
            if (prefixed) {
                String[] split = storedReference.split(":");
                if (split == null || split.length != 2) {
                    return obj;
                }
                if (split[0].equals(NuxeoPrincipal.PREFIX)) {
                    user = userManager.getUserModel(split[1]);
                } else if (split[0].equals(NuxeoGroup.PREFIX)) {
                    group = userManager.getGroupModel(split[1]);
                }
            } else {
                user = userManager.getUserModel(storedReference);
                if (user == null) {
                    group = userManager.getGroupModel(storedReference);
                }
            }
            if (user != null) {
                Schema schema = schemaManager.getSchema("user");
                String username = null;
                String firstname = null;
                String lastname = null;
                for (Field field : schema.getFields()) {
                    QName fieldName = field.getName();
                    String key = fieldName.getLocalName();
                    Serializable value = user.getPropertyValue(fieldName.getPrefixedName());
                    obj.element(key, value);
                    if (key.equals("username")) {
                        username = (String) value;
                    } else if (key.equals("firstName")) {
                        firstname = (String) value;
                    } else if (key.equals("lastName")) {
                        lastname = (String) value;
                    }
                }
                String label = "";
                if (firstname != null && !firstname.isEmpty()
                        && lastname != null && !lastname.isEmpty()) {
                    label = firstname + " " + lastname;
                } else {
                    label = username;
                }
                String userId = user.getId();
                obj.put(Select2Common.ID, userId);
                obj.put(Select2Common.LABEL, label);
                obj.put(Select2Common.TYPE_KEY_NAME, Select2Common.USER_TYPE);
                obj.put(Select2Common.PREFIXED_ID_KEY_NAME,
                        NuxeoPrincipal.PREFIX + userId);
            } else if (group != null) {
                Schema schema = schemaManager.getSchema("group");
                for (Field field : schema.getFields()) {
                    QName fieldName = field.getName();
                    String key = fieldName.getLocalName();
                    Serializable value = group.getPropertyValue(fieldName.getPrefixedName());
                    obj.element(key, value);
                    if (key.equals("grouplabel")) {
                        obj.element(Select2Common.LABEL, value);
                    }
                }
                String groupId = group.getId();
                obj.put(Select2Common.ID, groupId);
                obj.put(Select2Common.TYPE_KEY_NAME, Select2Common.GROUP_TYPE);
                obj.put(Select2Common.PREFIXED_ID_KEY_NAME, NuxeoGroup.PREFIX
                        + groupId);
            }
        } catch (ClientException e) {
            log.error("An error occured while retrievin user/group reference"
                    + storedReference);
            return null;
        }
        return obj;
    }

    public boolean isMultiSelection(final Widget widget) {
        WidgetTypeDefinition widgetTypeDefinition = getLayoutStore().getWidgetTypeDefinition(
                "jsf", widget.getType());<commit_msg>NXP-12264: fix wrong resoluion on prefixed user/group reference<commit_after>/*
 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * Contributors:
 *     <a href="mailto:<EMAIL>">Tiry</a>
 *     <a href="mailto:<EMAIL>">Guillaume</a>
 */

package org.nuxeo.ecm.platform.ui.select2;

import java.io.BufferedOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonGenerator;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.FacesLifecycle;
import org.nuxeo.ecm.automation.AutomationService;
import org.nuxeo.ecm.automation.InvalidChainException;
import org.nuxeo.ecm.automation.OperationContext;
import org.nuxeo.ecm.automation.OperationException;
import org.nuxeo.ecm.automation.jaxrs.io.JsonHelper;
import org.nuxeo.ecm.automation.jaxrs.io.documents.JsonDocumentWriter;
import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.CoreInstance;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.api.DocumentRef;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.NuxeoGroup;
import org.nuxeo.ecm.core.api.NuxeoPrincipal;
import org.nuxeo.ecm.core.api.PathRef;
import org.nuxeo.ecm.core.api.repository.Repository;
import org.nuxeo.ecm.core.api.repository.RepositoryManager;
import org.nuxeo.ecm.core.schema.SchemaManager;
import org.nuxeo.ecm.core.schema.types.Field;
import org.nuxeo.ecm.core.schema.types.QName;
import org.nuxeo.ecm.core.schema.types.Schema;
import org.nuxeo.ecm.directory.Directory;
import org.nuxeo.ecm.directory.DirectoryException;
import org.nuxeo.ecm.directory.Session;
import org.nuxeo.ecm.directory.api.DirectoryService;
import org.nuxeo.ecm.platform.forms.layout.api.Widget;
import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeDefinition;
import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore;
import org.nuxeo.ecm.platform.ui.select2.automation.SuggestUserEntries;
import org.nuxeo.ecm.platform.ui.select2.common.Select2Common;
import org.nuxeo.ecm.platform.url.DocumentViewImpl;
import org.nuxeo.ecm.platform.url.codec.DocumentIdCodec;
import org.nuxeo.ecm.platform.usermanager.UserManager;
import org.nuxeo.runtime.api.Framework;

/**
 * Initialization for Select2.
 *
 * @since 5.7.3
 */
@Name("select2Actions")
@Scope(ScopeType.EVENT)
public class Select2ActionsBean implements Serializable {

    private static final long serialVersionUID = 1L;

    @SuppressWarnings("unused")
    private static final Log log = LogFactory.getLog(Select2ActionsBean.class);

    protected static final String SELECT2_RESOURCES_MARKER = "SELECT2_RESOURCES_MARKER";

    private static List<String> formatList(JSONArray array) {
        List<String> result = new ArrayList<String>();
        if (array != null) {
            for (int i = 0; i < array.size(); i++) {
                result.add(array.getJSONObject(i).getString(Select2Common.LABEL));
            }
        }
        return result;
    }

    @In(create = true)
    protected Map<String, String> messages;

    @In(create = true, required = false)
    protected transient CoreSession documentManager;

    protected transient CoreSession dedicatedSession = null;

    @Destroy
    public void destroy() {
        if (dedicatedSession != null) {
            CoreInstance.getInstance().close(dedicatedSession);
        }
    }

    /**
     * Encode widget properties and parameters that Select2 pick them up in a
     * hidden input.
     *
     * @param widget the widget
     * @return encoded
     * @throws Exception
     *
     * @since 5.7.3
     */
    public String encodeParameters(final Widget widget) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedOutputStream out = new BufferedOutputStream(baos);

        JsonGenerator jg = JsonHelper.createJsonGenerator(out);
        jg.writeStartObject();

        // multiple is not in properties and we must add it because Select2
        // needs to know.
        jg.writeStringField("multiple", "" + isMultiSelection(widget));

        final boolean isTranslated = widget.isTranslated();

        // The operation might need to know if we translate the labels or not.
        jg.writeStringField("translateLabels", "" + isTranslated);

        Map<String, Serializable> propertySet = widget.getProperties();
        boolean hasPlaceholder = false, hasSuggestionFormatter = false, hasSelectionFormatter = false, hasAjaxReRender = false;

        for (Entry<String, Serializable> entry : propertySet.entrySet()) {

            String value = entry.getValue().toString();

            if (entry.getKey().equals(Select2Common.PLACEHOLDER)) {
                hasPlaceholder = true;
                // placeholder can be translated
                if (isTranslated) {
                    value = messages.get(entry.getValue().toString());
                }
            } else if (entry.getKey().equals(Select2Common.SUGGESTION_FORMATTER)) {
                hasSuggestionFormatter = true;
            } else if (entry.getKey().equals(Select2Common.SELECTION_FORMATTER)) {
                hasSelectionFormatter = true;
            } else if (entry.getKey().equals(Select2Common.AJAX_RERENDER)) {
                hasAjaxReRender = true;
            }

            jg.writeStringField(entry.getKey(), value);

        }

        if (!hasPlaceholder) {
            // No placeholder provider and Select2 requires one to enable the
            // reset button.
            jg.writeStringField(Select2Common.PLACEHOLDER,
                    messages.get("label.vocabulary.selectValue"));
        }

        // Had default selection and suggestion formatter if needed.
        if (widget.getType().startsWith(Select2Common.USER_SUGGESTION_SELECT2)) {
            jg.writeStringField("operationId", SuggestUserEntries.ID);
            if (!hasSuggestionFormatter) {
                jg.writeStringField(Select2Common.SUGGESTION_FORMATTER,
                        Select2Common.USER_DEFAULT_SUGGESTION_FORMATTER);
            }
            if (!hasSelectionFormatter) {
                jg.writeStringField(Select2Common.SELECTION_FORMATTER,
                        Select2Common.USER_DEFAULT_SELECTION_FORMATTER);
            }
        } else if (widget.getType().startsWith(Select2Common.SUGGESTION_SELECT2)) {
            if (!hasSuggestionFormatter) {
                jg.writeStringField(Select2Common.SUGGESTION_FORMATTER,
                        Select2Common.DOC_DEFAULT_SUGGESTION_FORMATTER);
            }
            if (!hasSelectionFormatter) {
                jg.writeStringField(Select2Common.SELECTION_FORMATTER,
                        Select2Common.DOC_DEFAULT_SELECTION_FORMATTER);
            }
        } else if (widget.getType().startsWith(
                Select2Common.DIR_SUGGESTION_SELECT2)) {
            if (!hasSuggestionFormatter) {
                jg.writeStringField(Select2Common.SUGGESTION_FORMATTER,
                        Select2Common.DIR_DEFAULT_SUGGESTION_FORMATTER);
            }
            if (!hasSelectionFormatter) {
                jg.writeStringField(Select2Common.SELECTION_FORMATTER,
                        Select2Common.DIR_DEFAULT_SELECTION_FORMATTER);
            }
        }

        // Are we writing or reading
        boolean readonly = !widget.getMode().equals("edit")
                && !widget.getMode().equals("create");
        jg.writeStringField(Select2Common.READ_ONLY_PARAM,
                Boolean.toString(readonly));
        if (hasAjaxReRender) {
            jg.writeStringField(Select2Common.RERENDER_JS_FUNCTION_NAME,
                    widget.getId() + "_reRender");
        }

        jg.writeEndObject();
        jg.flush();
        out.flush();
        return new String(baos.toByteArray(), "UTF-8");
    }

    protected LayoutStore getLayoutStore() {
        LayoutStore layoutStore = null;
        try {
            layoutStore = Framework.getLocalService(LayoutStore.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (layoutStore == null) {
            throw new RuntimeException("Missing service for LayoutStore");
        }
        return layoutStore;
    }

    protected JSONArray getMultipleDirectoryEntries(final Object value,
            final String directoryName, final boolean translateLabels,
            String keySeparator, final boolean dbl10n,
            final String labelFieldName) {
        JSONArray result = new JSONArray();
        if (value == null) {
            return result;
        }

        List<String> storedRefs = new ArrayList<>();
        if (value instanceof List) {
            for (Object v : (List) value) {
                storedRefs.add(v.toString());
            }
        } else if (value instanceof Object[]) {
            for (Object v : (Object[]) value) {
                storedRefs.add(v.toString());
            }
        }

        DirectoryService directoryService = Framework.getLocalService(DirectoryService.class);
        Directory directory = null;
        Session session = null;
        try {
            directory = directoryService.getDirectory(directoryName);
            if (directory == null) {
                log.error("Could not find directory with name " + directoryName);
                return result;
            }
            session = directory.getSession();
            String schemaName = directory.getSchema();
            SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
            Schema schema = schemaManager.getSchema(schemaName);
            final Locale locale = org.jboss.seam.core.Locale.instance();
            final String label = Select2Common.getLabelFieldName(schema,
                    dbl10n, labelFieldName, locale.getLanguage());

            for (String ref : storedRefs) {
                JSONObject obj = resolveDirectoryEntry(ref, keySeparator,
                        session, schema, label, translateLabels, dbl10n);
                if (obj != null) {
                    result.add(obj);
                }
            }
            return result;
        } catch (DirectoryException de) {
            log.error("An error occured while obtaining directory "
                    + directoryName, de);
            return result;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (ClientException ce) {
                log.error("Could not close directory session", ce);
            }
        }

    }

    protected JSONArray getMultipleUserReference(final Object value,
            final boolean prefixed) {
        if (value == null) {
            return null;
        }
        JSONArray result = new JSONArray();
        List<String> storedRefs = new ArrayList<>();
        if (value instanceof List) {
            for (Object v : (List) value) {
                storedRefs.add(v.toString());
            }
        } else if (value instanceof Object[]) {
            for (Object v : (Object[]) value) {
                storedRefs.add(v.toString());
            }
        }

        for (String ref : storedRefs) {
            JSONObject resolved = getSingleUserReference(ref, prefixed);
            if (resolved != null && !resolved.isEmpty()) {
                result.add(resolved);
            }
        }
        return result;
    }

    protected CoreSession getRepositorySession(final String repoName)
            throws ClientException {

        RepositoryManager rm = Framework.getLocalService(RepositoryManager.class);
        Repository repository = null;
        if (repoName == null || repoName.isEmpty()) {
            repository = rm.getDefaultRepository();
        } else {
            repository = rm.getRepository(repoName);
            if (repository == null) {
                log.error("Unable to resolve repository " + repoName);
                return null;
            }
        }

        if (documentManager != null
                && documentManager.getRepositoryName().equals(
                        repository.getName())) {
            return documentManager;
        }

        try {
            dedicatedSession = repository.open();
            return dedicatedSession;
        } catch (Exception e) {
            throw new ClientException(e);
        }
    }

    protected JSONObject getSingleDirectoryEntry(final String storedReference,
            final String directoryName, final boolean translateLabels,
            String keySeparator, final boolean dbl10n,
            final String labelFieldName) {

        if (storedReference == null || storedReference.isEmpty()) {
            return null;
        }

        DirectoryService directoryService = Framework.getLocalService(DirectoryService.class);
        Directory directory = null;
        Session session = null;
        try {
            directory = directoryService.getDirectory(directoryName);
            if (directory == null) {
                log.error("Could not find directory with name " + directoryName);
                return null;
            }
            session = directory.getSession();
            String schemaName = directory.getSchema();
            SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
            Schema schema = schemaManager.getSchema(schemaName);

            final Locale locale = org.jboss.seam.core.Locale.instance();
            final String label = Select2Common.getLabelFieldName(schema,
                    dbl10n, labelFieldName, locale.getLanguage());

            JSONObject obj = resolveDirectoryEntry(storedReference,
                    keySeparator, session, schema, label, translateLabels,
                    dbl10n);

            return obj;
        } catch (DirectoryException de) {
            log.error("An error occured while obtaining directory "
                    + directoryName, de);
            return null;
        } finally {
            try {
                if (session != null) {
                    session.close();
                }
            } catch (ClientException ce) {
                log.error("Could not close directory session", ce);
            }
        }

    }

    protected JSONObject getSingleUserReference(final String storedReference,
            final boolean prefixed) {
        UserManager userManager = Framework.getLocalService(UserManager.class);
        SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
        JSONObject obj = new JSONObject();
        if (storedReference == null || storedReference.isEmpty()) {
            return null;
        }
        try {
            DocumentModel user = null;
            DocumentModel group = null;
            if (prefixed) {
                if (storedReference.startsWith(NuxeoPrincipal.PREFIX)) {
                    user = userManager.getUserModel(storedReference.substring(NuxeoPrincipal.PREFIX.length()));
                } else if (storedReference.startsWith(NuxeoGroup.PREFIX)) {
                    group = userManager.getGroupModel(storedReference.substring(NuxeoGroup.PREFIX.length()));
                } else {
                    log.warn("User reference is prefixed but prefix was not found on reference: "
                            + storedReference);
                    return null;
                }
            } else {
                user = userManager.getUserModel(storedReference);
                if (user == null) {
                    group = userManager.getGroupModel(storedReference);
                }
            }
            if (user != null) {
                Schema schema = schemaManager.getSchema("user");
                String username = null;
                String firstname = null;
                String lastname = null;
                for (Field field : schema.getFields()) {
                    QName fieldName = field.getName();
                    String key = fieldName.getLocalName();
                    Serializable value = user.getPropertyValue(fieldName.getPrefixedName());
                    obj.element(key, value);
                    if (key.equals("username")) {
                        username = (String) value;
                    } else if (key.equals("firstName")) {
                        firstname = (String) value;
                    } else if (key.equals("lastName")) {
                        lastname = (String) value;
                    }
                }
                String label = "";
                if (firstname != null && !firstname.isEmpty()
                        && lastname != null && !lastname.isEmpty()) {
                    label = firstname + " " + lastname;
                } else {
                    label = username;
                }
                String userId = user.getId();
                obj.put(Select2Common.ID, userId);
                obj.put(Select2Common.LABEL, label);
                obj.put(Select2Common.TYPE_KEY_NAME, Select2Common.USER_TYPE);
                obj.put(Select2Common.PREFIXED_ID_KEY_NAME,
                        NuxeoPrincipal.PREFIX + userId);
            } else if (group != null) {
                Schema schema = schemaManager.getSchema("group");
                for (Field field : schema.getFields()) {
                    QName fieldName = field.getName();
                    String key = fieldName.getLocalName();
                    Serializable value = group.getPropertyValue(fieldName.getPrefixedName());
                    obj.element(key, value);
                    if (key.equals("grouplabel")) {
                        obj.element(Select2Common.LABEL, value);
                    }
                }
                String groupId = group.getId();
                obj.put(Select2Common.ID, groupId);
                obj.put(Select2Common.TYPE_KEY_NAME, Select2Common.GROUP_TYPE);
                obj.put(Select2Common.PREFIXED_ID_KEY_NAME, NuxeoGroup.PREFIX
                        + groupId);
            } else {
                log.warn("Could not resolve user or group reference: "
                        + storedReference);
                return null;
            }
        } catch (ClientException e) {
            log.error("An error occured while retrieving user or group reference: "
                    + storedReference);
            return null;
        }
        return obj;
    }

    public boolean isMultiSelection(final Widget widget) {
        WidgetTypeDefinition widgetTypeDefinition = getLayoutStore().getWidgetTypeDefinition(
                "jsf", widget.getType());
{'fraction_non_alphanumeric': 0.09431997154905249, 'fraction_numerical': 0.004216836864299142, 'mean_word_length': 2.0569187762074854, 'pattern_counts': {'":': 1, '<': 37, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2659169', 'n_tokens_mistral': 10501, 'n_tokens_neox': 10007, 'n_words': 2184}