001/*
002 * (C) Copyright 2015-2019 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.platform.usermanager.io;
021
022import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
023import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
024import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
025
026import java.io.IOException;
027import java.io.OutputStream;
028import java.util.Arrays;
029import java.util.Collection;
030import java.util.List;
031
032import javax.inject.Inject;
033
034import org.nuxeo.ecm.core.api.DocumentModel;
035import org.nuxeo.ecm.core.api.NuxeoGroup;
036import org.nuxeo.ecm.core.api.model.Property;
037import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter;
038import org.nuxeo.ecm.core.io.marshallers.json.OutputStreamWithJsonWriter;
039import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentPropertyJsonWriter;
040import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher;
041import org.nuxeo.ecm.core.io.registry.Writer;
042import org.nuxeo.ecm.core.io.registry.reflect.Setup;
043import org.nuxeo.ecm.platform.usermanager.UserManager;
044
045import com.fasterxml.jackson.core.JsonGenerator;
046
047/**
048 * Convert {@link NuxeoGroup} to Json.
049 * <p>
050 * This marshaller is enrichable: register class implementing {@link AbstractJsonEnricher} and managing
051 * {@link NuxeoGroup}.
052 * </p>
053 * <p>
054 * This marshaller is also extensible: extend it and simply override
055 * {@link ExtensibleEntityJsonWriter#extend(Object, JsonGenerator)}.
056 * </p>
057 * <p>
058 * Format is:
059 *
060 * <pre>
061 * {@code
062 * {
063 *   "entity-type":"group",
064 *   "groupname": "GROUP_NAME", <- deprecated, for backward compatibility
065 *   "grouplabel": "GROUP_DISPLAY_NAME", <- deprecated, for backward compatibility
066 *   "id": "GROUP_NAME",
067 *   "properties":{   <- depending on the group schema / format is managed by {@link DocumentPropertyJsonWriter }
068 *     "groupname":"GROUP_NAME",
069 *     "grouplabel":"GROUP_DISPLAY_NAME",
070 *     "description": "GROUP_DESCRIPTION"
071 *   },
072 *   "memberUsers": [
073 *     "USERNAME1",
074 *     "USERNAME2",
075 *     ...
076 *   ],
077 *   "memberGroups": [
078 *     "GROUPNAME1",
079 *     "GROUPNAME2",
080 *     ...
081 *   ],
082 *   "parentGroups": [
083 *     "GROUPNAME1",
084 *     "GROUPNAME2",
085 *     ...
086 *   ]
087 *             <-- contextParameters if there are enrichers activated
088 *             <-- additional property provided by extend() method
089 * }
090 * }
091 * </pre>
092 *
093 * @since 7.2
094 */
095@Setup(mode = SINGLETON, priority = REFERENCE)
096public class NuxeoGroupJsonWriter extends ExtensibleEntityJsonWriter<NuxeoGroup> {
097
098    public static final String ENTITY_TYPE = "group";
099
100    /**
101     * @since 9.3
102     */
103    public static final String MEMBER_USERS_FETCH_PROPERTY = "memberUsers";
104
105    /**
106     * @since 9.3
107     */
108    public static final String MEMBER_GROUPS_FETCH_PROPERTY = "memberGroups";
109
110    /**
111     * @since 9.3
112     */
113    public static final String PARENT_GROUPS_FETCH_PROPERTY = "parentGroups";
114
115    /**
116     * @since 9.3
117     */
118    public static final String GROUP_NAME_COMPATIBILITY_FIELD = "groupname";
119
120    /**
121     * @since 9.3
122     */
123    public static final String GROUP_LABEL_COMPATIBILITY_FIELD = "grouplabel";
124
125    @Inject
126    private UserManager userManager;
127
128    public NuxeoGroupJsonWriter() {
129        super(ENTITY_TYPE, NuxeoGroup.class);
130    }
131
132    @Override
133    protected void writeEntityBody(NuxeoGroup group, JsonGenerator jg) throws IOException {
134        // for backward compatibility, those are now in the 'properties' field
135        jg.writeStringField(GROUP_NAME_COMPATIBILITY_FIELD, group.getName());
136        jg.writeStringField(GROUP_LABEL_COMPATIBILITY_FIELD, group.getLabel());
137
138        jg.writeStringField("id", group.getName());
139        writeProperties(group, jg);
140        writeMemberUsers(group, jg);
141        writeMemberGroups(group, jg);
142        writeParentGroups(group, jg);
143    }
144
145    protected void writeProperties(NuxeoGroup group, JsonGenerator jg) throws IOException {
146        DocumentModel doc = group.getModel();
147        if (doc == null) {
148            return;
149        }
150        String groupSchema = userManager.getGroupSchemaName();
151        Collection<Property> properties = doc.getPropertyObjects(groupSchema);
152        if (properties.isEmpty()) {
153            return;
154        }
155
156        List<String> excludedProperties = Arrays.asList(userManager.getGroupMembersField(),
157                userManager.getGroupSubGroupsField(), userManager.getGroupParentGroupsField());
158        Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE);
159        jg.writeObjectFieldStart("properties");
160        for (Property property : properties) {
161            String localName = property.getField().getName().getLocalName();
162            if (!excludedProperties.contains(localName)) {
163                jg.writeFieldName(localName);
164                OutputStream out = new OutputStreamWithJsonWriter(jg);
165                propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, out);
166            }
167        }
168        jg.writeEndObject();
169    }
170
171    protected void writeMemberUsers(NuxeoGroup group, JsonGenerator jg) throws IOException {
172        if (ctx.getFetched(ENTITY_TYPE).contains(MEMBER_USERS_FETCH_PROPERTY)) {
173            jg.writeArrayFieldStart(MEMBER_USERS_FETCH_PROPERTY);
174            for (String user : group.getMemberUsers()) {
175                jg.writeString(user);
176            }
177            jg.writeEndArray();
178        }
179    }
180
181    protected void writeMemberGroups(NuxeoGroup group, JsonGenerator jg) throws IOException {
182        if (ctx.getFetched(ENTITY_TYPE).contains(MEMBER_GROUPS_FETCH_PROPERTY)) {
183            jg.writeArrayFieldStart(MEMBER_GROUPS_FETCH_PROPERTY);
184            for (String user : group.getMemberGroups()) {
185                jg.writeString(user);
186            }
187            jg.writeEndArray();
188        }
189    }
190
191    protected void writeParentGroups(NuxeoGroup group, JsonGenerator jg) throws IOException {
192        if (ctx.getFetched(ENTITY_TYPE).contains(PARENT_GROUPS_FETCH_PROPERTY)) {
193            jg.writeArrayFieldStart(PARENT_GROUPS_FETCH_PROPERTY);
194            for (String user : group.getParentGroups()) {
195                jg.writeString(user);
196            }
197            jg.writeEndArray();
198        }
199    }
200
201}