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.codehaus.jackson.JsonGenerator;
035import org.nuxeo.ecm.core.api.DocumentModel;
036import org.nuxeo.ecm.core.api.NuxeoGroup;
037import org.nuxeo.ecm.core.api.model.Property;
038import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter;
039import org.nuxeo.ecm.core.io.marshallers.json.OutputStreamWithJsonWriter;
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.thoughtworks.xstream.io.json.JsonWriter;
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(NuxeoGroup, JsonWriter)}.
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 * </pre>
091 * </p>
092 * @since 7.2
093 */
094@Setup(mode = SINGLETON, priority = REFERENCE)
095public class NuxeoGroupJsonWriter extends ExtensibleEntityJsonWriter<NuxeoGroup> {
096
097    public static final String ENTITY_TYPE = "group";
098
099    /**
100     * @since 9.3
101     */
102    public static final String MEMBER_USERS_FETCH_PROPERTY = "memberUsers";
103
104    /**
105     * @since 9.3
106     */
107    public static final String MEMBER_GROUPS_FETCH_PROPERTY = "memberGroups";
108
109    /**
110     * @since 9.3
111     */
112    public static final String PARENT_GROUPS_FETCH_PROPERTY = "parentGroups";
113
114    /**
115     * @since 9.3
116     */
117    public static final String GROUP_NAME_COMPATIBILITY_FIELD = "groupname";
118
119    /**
120     * @since 9.3
121     */
122    public static final String GROUP_LABEL_COMPATIBILITY_FIELD = "grouplabel";
123
124    @Inject
125    private UserManager userManager;
126
127    public NuxeoGroupJsonWriter() {
128        super(ENTITY_TYPE, NuxeoGroup.class);
129    }
130
131    @Override
132    protected void writeEntityBody(NuxeoGroup group, JsonGenerator jg) throws IOException {
133        // for backward compatibility, those are now in the 'properties' field
134        jg.writeStringField(GROUP_NAME_COMPATIBILITY_FIELD, group.getName());
135        jg.writeStringField(GROUP_LABEL_COMPATIBILITY_FIELD, group.getLabel());
136
137        jg.writeStringField("id", group.getName());
138        writeProperties(group, jg);
139        writeMemberUsers(group, jg);
140        writeMemberGroups(group, jg);
141        writeParentGroups(group, jg);
142    }
143
144    protected void writeProperties(NuxeoGroup group, JsonGenerator jg) throws IOException {
145        DocumentModel doc = group.getModel();
146        if (doc == null) {
147            return;
148        }
149        String groupSchema = userManager.getGroupSchemaName();
150        Collection<Property> properties = doc.getPropertyObjects(groupSchema);
151        if (properties.isEmpty()) {
152            return;
153        }
154
155        List<String> excludedProperties = Arrays.asList(userManager.getGroupMembersField(),
156                userManager.getGroupSubGroupsField(), userManager.getGroupParentGroupsField());
157        Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE);
158        jg.writeObjectFieldStart("properties");
159        for (Property property : properties) {
160            String localName = property.getField().getName().getLocalName();
161            if (!excludedProperties.contains(localName)) {
162                jg.writeFieldName(localName);
163                OutputStream out = new OutputStreamWithJsonWriter(jg);
164                propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, out);
165            }
166        }
167        jg.writeEndObject();
168    }
169
170    protected void writeMemberUsers(NuxeoGroup group, JsonGenerator jg) throws IOException {
171        if (ctx.getFetched(ENTITY_TYPE).contains(MEMBER_USERS_FETCH_PROPERTY)) {
172            jg.writeArrayFieldStart(MEMBER_USERS_FETCH_PROPERTY);
173            for (String user : group.getMemberUsers()) {
174                jg.writeString(user);
175            }
176            jg.writeEndArray();
177        }
178    }
179
180    protected void writeMemberGroups(NuxeoGroup group, JsonGenerator jg) throws IOException {
181        if (ctx.getFetched(ENTITY_TYPE).contains(MEMBER_GROUPS_FETCH_PROPERTY)) {
182            jg.writeArrayFieldStart(MEMBER_GROUPS_FETCH_PROPERTY);
183            for (String user : group.getMemberGroups()) {
184                jg.writeString(user);
185            }
186            jg.writeEndArray();
187        }
188    }
189
190    protected void writeParentGroups(NuxeoGroup group, JsonGenerator jg) throws IOException {
191        if (ctx.getFetched(ENTITY_TYPE).contains(PARENT_GROUPS_FETCH_PROPERTY)) {
192            jg.writeArrayFieldStart(PARENT_GROUPS_FETCH_PROPERTY);
193            for (String user : group.getParentGroups()) {
194                jg.writeString(user);
195            }
196            jg.writeEndArray();
197        }
198    }
199
200}