001/* 002 * (C) Copyright 2013 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 * dmetzler 018 */ 019package org.nuxeo.ecm.automation.io.services.enricher; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.Collections; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Map.Entry; 029import java.util.Set; 030import java.util.concurrent.ConcurrentHashMap; 031 032import javax.ws.rs.core.HttpHeaders; 033 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036import org.codehaus.jackson.JsonGenerationException; 037import org.codehaus.jackson.JsonGenerator; 038import org.jboss.el.ExpressionFactoryImpl; 039import org.nuxeo.common.utils.StringUtils; 040import org.nuxeo.ecm.core.api.CoreSession; 041import org.nuxeo.ecm.core.api.NuxeoPrincipal; 042import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher; 043import org.nuxeo.ecm.platform.actions.ActionContext; 044import org.nuxeo.ecm.platform.actions.ELActionContext; 045import org.nuxeo.ecm.platform.actions.ejb.ActionManager; 046import org.nuxeo.ecm.platform.el.ExpressionContext; 047import org.nuxeo.runtime.api.Framework; 048import org.nuxeo.runtime.model.ComponentContext; 049import org.nuxeo.runtime.model.ComponentInstance; 050import org.nuxeo.runtime.model.DefaultComponent; 051 052/** 053 * @since 5.7.3 054 * @deprecated The JSON marshalling was migrated to nuxeo-core-io. An enricher system is also available. See 055 * org.nuxeo.ecm.core.io.marshallers.json.enrichers.BreadcrumbJsonEnricher for an example. To migrate an 056 * existing enricher, keep the marshalling code and use it in class implementing 057 * AbstractJsonEnricher<DocumentModel> (the use of contextual parameters is a bit different but 058 * compatible / you have to manage the enricher's parameters yourself). Don't forget to contribute to 059 * service org.nuxeo.ecm.core.io.registry.MarshallerRegistry to register your enricher. 060 */ 061@Deprecated 062public class ContentEnricherServiceImpl extends DefaultComponent implements ContentEnricherService { 063 064 /** 065 * 066 */ 067 public static final String NXCONTENT_CATEGORY_HEADER = "X-NXContext-Category"; 068 069 protected static final Log log = LogFactory.getLog(ContentEnricherServiceImpl.class); 070 071 public static final String ENRICHER = "enricher"; 072 073 public static List<Class<?>> DEPRECATED_KNOWN_ENRICHERS = Arrays.asList(ACLContentEnricher.class, 074 PreviewContentEnricher.class, ThumbnailContentEnricher.class, UserPermissionsContentEnricher.class); 075 076 private Map<String, ContentEnricherDescriptor> descriptorRegistry = new ConcurrentHashMap<>(); 077 078 private Set<Class<?>> customEnrichers = Collections.synchronizedSet(new HashSet<>()); 079 080 @Override 081 public void activate(ComponentContext context) { 082 super.activate(context); 083 List<String> customDeprecated = new ArrayList<>(); 084 List<Class<?>> deprecatedKnown = Arrays.asList(ACLContentEnricher.class, PreviewContentEnricher.class, 085 ThumbnailContentEnricher.class, UserPermissionsContentEnricher.class); 086 for (ContentEnricherDescriptor descriptor : descriptorRegistry.values()) { 087 if (!deprecatedKnown.contains(descriptor.klass)) { 088 customDeprecated.add(descriptor.klass.getSimpleName()); 089 } 090 } 091 if (!customDeprecated.isEmpty()) { 092 log.warn("The ContentEnricherService is deprecated since 7.10. The contributed enrichers are still available through the deprecated JAX-RS document's marshallers but won't be available through the REST API or automation. You should migrate the following classes and implement " 093 + AbstractJsonEnricher.class.getName() + ": " + StringUtils.join(customDeprecated, ',')); 094 } 095 } 096 097 @Override 098 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 099 100 if (ENRICHER.equals(extensionPoint)) { 101 ContentEnricherDescriptor cd = (ContentEnricherDescriptor) contribution; 102 if (!DEPRECATED_KNOWN_ENRICHERS.contains(cd.klass)) { 103 if (customEnrichers.isEmpty()) { 104 log.warn("The ContentEnricherService is deprecated since 7.10. The contributed enrichers are still available for use through the deprecated JAX-RS document's marshallers but won't be available through the default Nuxeo REST API or Nuxeo Automation. You should migrate your enrichers and implement " 105 + AbstractJsonEnricher.class.getName()); 106 } 107 if (!customEnrichers.contains(cd.klass)) { 108 customEnrichers.add(cd.klass); 109 log.warn("Enrichers registered and not available for use in Nuxeo Rest API and Nuxeo Automation: " 110 + cd.klass.getName()); 111 } 112 } 113 descriptorRegistry.put(cd.name, cd); 114 } 115 116 } 117 118 @Override 119 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 120 if (ENRICHER.equals(extensionPoint)) { 121 ContentEnricherDescriptor cd = (ContentEnricherDescriptor) contribution; 122 if (descriptorRegistry.containsKey(cd.name)) { 123 descriptorRegistry.remove(cd.name); 124 if (!DEPRECATED_KNOWN_ENRICHERS.contains(cd.klass)) { 125 customEnrichers.remove(cd.name); 126 } 127 } 128 } 129 } 130 131 @Override 132 public List<ContentEnricher> getEnrichers(String category, RestEvaluationContext context) { 133 List<ContentEnricher> result = new ArrayList<>(); 134 for (ContentEnricherDescriptor descriptor : getEnricherDescriptors(category, context)) { 135 136 ContentEnricher contentEnricher = descriptor.getContentEnricher(); 137 result.add(contentEnricher); 138 } 139 140 return result; 141 } 142 143 private List<ContentEnricherDescriptor> getEnricherDescriptors(String category, RestEvaluationContext context) { 144 List<ContentEnricherDescriptor> result = new ArrayList<>(); 145 for (Entry<String, ContentEnricherDescriptor> entry : descriptorRegistry.entrySet()) { 146 ContentEnricherDescriptor descriptor = entry.getValue(); 147 if (descriptor.categories.contains(category)) { 148 result.add(descriptor); 149 } 150 } 151 return result; 152 } 153 154 @Override 155 public void writeContext(JsonGenerator jg, RestEvaluationContext ec) throws JsonGenerationException, IOException { 156 157 for (String category : getCategoriesToActivate(ec)) { 158 for (ContentEnricherDescriptor descriptor : getEnricherDescriptors(category, ec)) { 159 if (evaluateFilter(ec, descriptor)) { 160 ContentEnricher enricher = descriptor.getContentEnricher(); 161 if (enricher != null) { 162 jg.writeFieldName(descriptor.name); 163 enricher.enrich(jg, ec); 164 } 165 } 166 } 167 } 168 169 } 170 171 /** 172 * @param ec 173 * @param descriptor 174 * @return 175 */ 176 private boolean evaluateFilter(RestEvaluationContext ec, ContentEnricherDescriptor descriptor) { 177 for (String filterId : descriptor.filterIds) { 178 ActionManager as = Framework.getLocalService(ActionManager.class); 179 if (!as.checkFilter(filterId, createActionContext(ec))) { 180 return false; 181 } 182 } 183 return true; 184 } 185 186 /** 187 * Creates an ActionService compatible ActionContext to evaluate filters 188 * 189 * @param ec 190 * @return 191 */ 192 private ActionContext createActionContext(RestEvaluationContext ec) { 193 ActionContext actionContext = new ELActionContext(new ExpressionContext(), new ExpressionFactoryImpl()); 194 CoreSession session = ec.getDocumentModel().getCoreSession(); 195 actionContext.setDocumentManager(session); 196 actionContext.setCurrentPrincipal((NuxeoPrincipal) session.getPrincipal()); 197 198 actionContext.setCurrentDocument(ec.getDocumentModel()); 199 200 return actionContext; 201 } 202 203 private List<String> getCategoriesToActivate(RestEvaluationContext ec) { 204 HttpHeaders headers = ec.getHeaders(); 205 if (headers != null) { 206 List<String> requestHeader = headers.getRequestHeader(NXCONTENT_CATEGORY_HEADER); 207 if (requestHeader != null && !requestHeader.isEmpty()) { 208 return Arrays.asList(StringUtils.split(requestHeader.get(0), ',', true)); 209 } else { 210 return new ArrayList<>(0); 211 } 212 } 213 return new ArrayList<>(0); 214 } 215 216}