001package org.nuxeo.ecm.automation.jaxrs.io.documents; 002 003import static org.nuxeo.ecm.core.api.security.SecurityConstants.BROWSE; 004import static org.nuxeo.ecm.core.api.security.SecurityConstants.EVERYONE; 005import static org.nuxeo.ecm.core.api.security.SecurityConstants.UNSUPPORTED_ACL; 006 007import java.io.IOException; 008import java.io.OutputStream; 009import java.lang.annotation.Annotation; 010import java.lang.reflect.Type; 011import java.util.ArrayList; 012import java.util.Arrays; 013import java.util.List; 014import java.util.Map; 015 016import javax.ws.rs.Produces; 017import javax.ws.rs.core.HttpHeaders; 018import javax.ws.rs.core.MediaType; 019import javax.ws.rs.ext.Provider; 020 021import org.codehaus.jackson.JsonEncoding; 022import org.codehaus.jackson.JsonGenerator; 023import org.nuxeo.ecm.core.api.DocumentModel; 024import org.nuxeo.ecm.core.api.DocumentRef; 025import org.nuxeo.ecm.core.api.security.ACE; 026import org.nuxeo.ecm.core.api.security.ACL; 027import org.nuxeo.ecm.core.api.security.ACP; 028import org.nuxeo.ecm.core.api.security.impl.ACPImpl; 029import org.nuxeo.ecm.core.security.SecurityService; 030import org.nuxeo.ecm.platform.tag.Tag; 031import org.nuxeo.ecm.platform.tag.TagService; 032import org.nuxeo.runtime.api.Framework; 033 034/** 035 * JSon writer that outputs a format ready to eat by elasticsearch. 036 * 037 * @since 5.9.3 038 */ 039@Provider 040@Produces({ JsonESDocumentWriter.MIME_TYPE }) 041public class JsonESDocumentWriter extends JsonDocumentWriter { 042 043 public static final String MIME_TYPE = "application/json+esentity"; 044 045 @Override 046 public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 047 return super.isWriteable(type, genericType, annotations, mediaType) && MIME_TYPE.equals(mediaType.toString()); 048 } 049 050 public void writeDoc(JsonGenerator jg, DocumentModel doc, String[] schemas, Map<String, String> contextParameters, 051 HttpHeaders headers) throws IOException { 052 053 jg.writeStartObject(); 054 writeSystemProperties(jg, doc); 055 writeSchemas(jg, doc, schemas); 056 writeContextParameters(jg, doc, contextParameters); 057 jg.writeEndObject(); 058 jg.flush(); 059 } 060 061 /** 062 * @since 7.2 063 */ 064 protected void writeSystemProperties(JsonGenerator jg, DocumentModel doc) throws IOException { 065 jg.writeStringField("ecm:repository", doc.getRepositoryName()); 066 jg.writeStringField("ecm:uuid", doc.getId()); 067 jg.writeStringField("ecm:name", doc.getName()); 068 jg.writeStringField("ecm:title", doc.getTitle()); 069 jg.writeStringField("ecm:path", doc.getPathAsString()); 070 jg.writeStringField("ecm:primaryType", doc.getType()); 071 DocumentRef parentRef = doc.getParentRef(); 072 if (parentRef != null) { 073 jg.writeStringField("ecm:parentId", parentRef.toString()); 074 } 075 jg.writeStringField("ecm:currentLifeCycleState", doc.getCurrentLifeCycleState()); 076 jg.writeStringField("ecm:versionLabel", doc.getVersionLabel()); 077 jg.writeBooleanField("ecm:isCheckedIn", !doc.isCheckedOut()); 078 jg.writeBooleanField("ecm:isProxy", doc.isProxy()); 079 jg.writeBooleanField("ecm:isVersion", doc.isVersion()); 080 jg.writeBooleanField("ecm:isLatestVersion", doc.isLatestVersion()); 081 jg.writeBooleanField("ecm:isLatestMajorVersion", doc.isLatestMajorVersion()); 082 jg.writeArrayFieldStart("ecm:mixinType"); 083 for (String facet : doc.getFacets()) { 084 jg.writeString(facet); 085 } 086 jg.writeEndArray(); 087 TagService tagService = Framework.getService(TagService.class); 088 if (tagService != null) { 089 jg.writeArrayFieldStart("ecm:tag"); 090 for (Tag tag : tagService.getDocumentTags(doc.getCoreSession(), doc.getId(), null, true)) { 091 jg.writeString(tag.getLabel()); 092 } 093 jg.writeEndArray(); 094 } 095 jg.writeStringField("ecm:changeToken", doc.getChangeToken()); 096 Long pos = doc.getPos(); 097 if (pos != null) { 098 jg.writeNumberField("ecm:pos", pos); 099 } 100 // Add a positive ACL only 101 SecurityService securityService = Framework.getService(SecurityService.class); 102 List<String> browsePermissions = new ArrayList<String>( 103 Arrays.asList(securityService.getPermissionsToCheck(BROWSE))); 104 ACP acp = doc.getACP(); 105 if (acp == null) { 106 acp = new ACPImpl(); 107 } 108 jg.writeArrayFieldStart("ecm:acl"); 109 outerloop: for (ACL acl : acp.getACLs()) { 110 for (ACE ace : acl.getACEs()) { 111 if (ace.isGranted() && ace.isEffective() && browsePermissions.contains(ace.getPermission())) { 112 jg.writeString(ace.getUsername()); 113 } 114 if (ace.isDenied() && ace.isEffective()) { 115 if (!EVERYONE.equals(ace.getUsername())) { 116 jg.writeString(UNSUPPORTED_ACL); 117 } 118 break outerloop; 119 } 120 } 121 } 122 123 jg.writeEndArray(); 124 Map<String, String> bmap = doc.getBinaryFulltext(); 125 if (bmap != null && !bmap.isEmpty()) { 126 for (Map.Entry<String, String> item : bmap.entrySet()) { 127 String value = item.getValue(); 128 if (value != null) { 129 jg.writeStringField("ecm:" + item.getKey(), value); 130 } 131 } 132 } 133 } 134 135 /** 136 * @since 7.2 137 */ 138 protected void writeSchemas(JsonGenerator jg, DocumentModel doc, String[] schemas) throws IOException { 139 if (schemas == null || (schemas.length == 1 && "*".equals(schemas[0]))) { 140 schemas = doc.getSchemas(); 141 } 142 for (String schema : schemas) { 143 writeProperties(jg, doc, schema, null); 144 } 145 } 146 147 /** 148 * @since 7.2 149 */ 150 protected void writeContextParameters(JsonGenerator jg, DocumentModel doc, Map<String, String> contextParameters) 151 throws IOException { 152 if (contextParameters != null && !contextParameters.isEmpty()) { 153 for (Map.Entry<String, String> parameter : contextParameters.entrySet()) { 154 jg.writeStringField(parameter.getKey(), parameter.getValue()); 155 } 156 } 157 } 158 159 @Override 160 public void writeDocument(OutputStream out, DocumentModel doc, String[] schemas, 161 Map<String, String> contextParameters) throws IOException { 162 writeDoc(factory.createJsonGenerator(out, JsonEncoding.UTF8), doc, schemas, contextParameters, headers); 163 } 164 165 public void writeESDocument(JsonGenerator jg, DocumentModel doc, String[] schemas, 166 Map<String, String> contextParameters) throws IOException { 167 writeDoc(jg, doc, schemas, contextParameters, null); 168 } 169}