001/*
002 * (C) Copyright 2015 Nuxeo SA (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.enrichers.AbstractJsonEnricher;
040import org.nuxeo.ecm.core.io.registry.Writer;
041import org.nuxeo.ecm.core.io.registry.reflect.Setup;
042import org.nuxeo.ecm.platform.usermanager.UserManager;
043
044import com.fasterxml.jackson.core.JsonGenerator;
045
046/**
047 * Convert {@link NuxeoGroup} to Json.
048 * <p>
049 * This marshaller is enrichable: register class implementing {@link AbstractJsonEnricher} and managing
050 * {@link NuxeoGroup}.
051 * </p>
052 * <p>
053 * This marshaller is also extensible: extend it and simply override
054 * {@link ExtensibleEntityJsonWriter#extend(NuxeoGroup, JsonWriter)}.
055 * </p>
056 * <p>
057 * Format is:
058 *
059 * <pre>
060 * {@code
061 * {
062 *   "entity-type":"group",
063 *   "groupname": "GROUP_NAME", <- deprecated, for backward compatibility
064 *   "grouplabel": "GROUP_DISPLAY_NAME", <- deprecated, for backward compatibility
065 *   "id": "GROUP_NAME",
066 *   "properties":{   <- depending on the group schema / format is managed by {@link DocumentPropertyJsonWriter}
067 *     "groupname":"GROUP_NAME",
068 *     "grouplabel":"GROUP_DISPLAY_NAME",
069 *     "description": "GROUP_DESCRIPTION"
070 *   },
071 *   "memberUsers": [
072 *     "USERNAME1",
073 *     "USERNAME2",
074 *     ...
075 *   ],
076 *   "memberGroups": [
077 *     "GROUPNAME1",
078 *     "GROUPNAME2",
079 *     ...
080 *   ],
081 *   "parentGroups": [
082 *     "GROUPNAME1",
083 *     "GROUPNAME2",
084 *     ...
085 *   ]
086 *             <-- contextParameters if there are enrichers activated
087 *             <-- additional property provided by extend() method
088 * }
089 * </pre>
090 * </p>
091 * @since 7.2
092 */
093@Setup(mode = SINGLETON, priority = REFERENCE)
094public class NuxeoGroupJsonWriter extends ExtensibleEntityJsonWriter<NuxeoGroup> {
095
096    public static final String ENTITY_TYPE = "group";
097
098    /**
099     * @since 9.3
100     */
101    public static final String MEMBER_USERS_FETCH_PROPERTY = "memberUsers";
102
103    /**
104     * @since 9.3
105     */
106    public static final String MEMBER_GROUPS_FETCH_PROPERTY = "memberGroups";
107
108    /**
109     * @since 9.3
110     */
111    public static final String PARENT_GROUPS_FETCH_PROPERTY = "parentGroups";
112
113    /**
114     * @since 9.3
115     */
116    public static final String GROUP_NAME_COMPATIBILITY_FIELD = "groupname";
117
118    /**
119     * @since 9.3
120     */
121    public static final String GROUP_LABEL_COMPATIBILITY_FIELD = "grouplabel";
122
123    @Inject
124    private UserManager userManager;
125
126    public NuxeoGroupJsonWriter() {
127        super(ENTITY_TYPE, NuxeoGroup.class);
128    }
129
130    @Override
131    protected void writeEntityBody(NuxeoGroup group, JsonGenerator jg) throws IOException {
132        // for backward compatibility, those are now in the 'properties' field
133        jg.writeStringField(GROUP_NAME_COMPATIBILITY_FIELD, group.getName());
134        jg.writeStringField(GROUP_LABEL_COMPATIBILITY_FIELD, group.getLabel());
135
136        jg.writeStringField("id", group.getName());
137        writeProperties(group, jg);
138        writeMemberUsers(group, jg);
139        writeMemberGroups(group, jg);
140        writeParentGroups(group, jg);
141    }
142
143    protected void writeProperties(NuxeoGroup group, JsonGenerator jg) throws IOException {
144        DocumentModel doc = group.getModel();
145        if (doc == null) {
146            return;
147        }
148        String groupSchema = userManager.getGroupSchemaName();
149        Collection<Property> properties = doc.getPropertyObjects(groupSchema);
150        if (properties.isEmpty()) {
151            return;
152        }
153
154        List<String> excludedProperties = Arrays.asList(userManager.getGroupMembersField(),
155                userManager.getGroupSubGroupsField(), userManager.getGroupParentGroupsField());
156        Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE);
157        jg.writeObjectFieldStart("properties");
158        for (Property property : properties) {
159            String localName = property.getField().getName().getLocalName();
160            if (!excludedProperties.contains(localName)) {
161                jg.writeFieldName(localName);
162                OutputStream out = new OutputStreamWithJsonWriter(jg);
163                propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, out);
164            }
165        }
166        jg.writeEndObject();
167    }
168
169    protected void writeMemberUsers(NuxeoGroup group, JsonGenerator jg) throws IOException {
170        if (ctx.getFetched(ENTITY_TYPE).contains(MEMBER_USERS_FETCH_PROPERTY)) {
171            jg.writeArrayFieldStart(MEMBER_USERS_FETCH_PROPERTY);
172            for (String user : group.getMemberUsers()) {
173                jg.writeString(user);
174            }
175            jg.writeEndArray();
176        }
177    }
178
179    protected void writeMemberGroups(NuxeoGroup group, JsonGenerator jg) throws IOException {
180        if (ctx.getFetched(ENTITY_TYPE).contains(MEMBER_GROUPS_FETCH_PROPERTY)) {
181            jg.writeArrayFieldStart(MEMBER_GROUPS_FETCH_PROPERTY);
182            for (String user : group.getMemberGroups()) {
183                jg.writeString(user);
184            }
185            jg.writeEndArray();
186        }
187    }
188
189    protected void writeParentGroups(NuxeoGroup group, JsonGenerator jg) throws IOException {
190        if (ctx.getFetched(ENTITY_TYPE).contains(PARENT_GROUPS_FETCH_PROPERTY)) {
191            jg.writeArrayFieldStart(PARENT_GROUPS_FETCH_PROPERTY);
192            for (String user : group.getParentGroups()) {
193                jg.writeString(user);
194            }
195            jg.writeEndArray();
196        }
197    }
198
199}