001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * bstefanescu 011 * vpasquier 012 * slacoin 013 */ 014package org.nuxeo.ecm.automation.server; 015 016import java.security.Principal; 017import java.util.ArrayList; 018import java.util.HashMap; 019import java.util.List; 020import java.util.Map; 021 022import javax.servlet.http.HttpServletRequest; 023import javax.ws.rs.ext.MessageBodyReader; 024import javax.ws.rs.ext.MessageBodyWriter; 025 026import org.codehaus.jackson.JsonFactory; 027import org.nuxeo.ecm.automation.core.Constants; 028import org.nuxeo.ecm.automation.io.services.IOComponent; 029import org.nuxeo.ecm.core.api.NuxeoPrincipal; 030import org.nuxeo.ecm.webengine.JsonFactoryManager; 031import org.nuxeo.runtime.api.Framework; 032import org.nuxeo.runtime.model.ComponentContext; 033import org.nuxeo.runtime.model.ComponentInstance; 034import org.nuxeo.runtime.model.DefaultComponent; 035 036/** 037 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 038 */ 039public class AutomationServerComponent extends DefaultComponent implements AutomationServer { 040 041 /** 042 * Was used to get the JsonFactory, but since 5.7.3 use either: * 043 * <code>{@link JsonFactoryManager#getJsonFactory()}</code> * Context annotation in JAX-RS object (providers or 044 * resources) 045 */ 046 @Deprecated 047 public static AutomationServerComponent me; 048 049 protected static final String XP_BINDINGS = "bindings"; 050 051 protected static final String IOCOMPONENT_NAME = "org.nuxeo.ecm.automation.io.services.IOComponent"; 052 053 protected IOComponent ioComponent; 054 055 private static final String XP_MARSHALLER = "marshallers"; 056 057 protected Map<String, RestBinding> bindings; 058 059 protected static final String XP_CODECS = "codecs"; 060 061 protected volatile Map<String, RestBinding> lookup; 062 063 protected List<Class<? extends MessageBodyWriter<?>>> writers; 064 065 protected List<Class<? extends MessageBodyReader<?>>> readers; 066 067 @Override 068 public void activate(ComponentContext context) { 069 bindings = new HashMap<String, RestBinding>(); 070 writers = new ArrayList<>(); 071 readers = new ArrayList<>(); 072 me = this; 073 ioComponent = ((IOComponent) Framework.getRuntime().getComponentInstance(IOCOMPONENT_NAME).getInstance()); 074 } 075 076 @Override 077 public void deactivate(ComponentContext context) { 078 bindings = null; 079 me = null; 080 } 081 082 @Override 083 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 084 if (XP_BINDINGS.equals(extensionPoint)) { 085 RestBinding binding = (RestBinding) contribution; 086 addBinding(binding); 087 } else if (XP_MARSHALLER.equals(extensionPoint)) { 088 MarshallerDescriptor marshaller = (MarshallerDescriptor) contribution; 089 writers.addAll(marshaller.getWriters()); 090 readers.addAll(marshaller.getReaders()); 091 } else if (XP_CODECS.equals(extensionPoint)) { 092 ioComponent.registerContribution(contribution, extensionPoint, contributor); 093 } 094 } 095 096 @Override 097 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 098 if (XP_BINDINGS.equals(extensionPoint)) { 099 RestBinding binding = (RestBinding) contribution; 100 removeBinding(binding); 101 } else if (XP_CODECS.equals(extensionPoint)) { 102 ioComponent.unregisterContribution(contribution, extensionPoint, contributor); 103 } 104 } 105 106 @Override 107 public <T> T getAdapter(Class<T> adapter) { 108 if (AutomationServer.class.isAssignableFrom(adapter)) { 109 return adapter.cast(this); 110 } 111 return null; 112 } 113 114 @Override 115 public void applicationStarted(ComponentContext context) { 116 super.applicationStarted(context); 117 } 118 119 /** 120 * Since 5.7.3, use {@link JsonFactoryManager#getJsonFactory()} 121 */ 122 @Deprecated 123 public JsonFactory getFactory() { 124 return Framework.getLocalService(JsonFactoryManager.class).getJsonFactory(); 125 } 126 127 @Override 128 public RestBinding getOperationBinding(String name) { 129 return lookup().get(name); 130 } 131 132 @Override 133 public RestBinding getChainBinding(String name) { 134 return lookup().get(Constants.CHAIN_ID_PREFIX + name); 135 } 136 137 @Override 138 public RestBinding[] getBindings() { 139 Map<String, RestBinding> map = lookup(); 140 return map.values().toArray(new RestBinding[map.size()]); 141 } 142 143 protected String getBindingKey(RestBinding binding) { 144 return binding.isChain() ? Constants.CHAIN_ID_PREFIX + binding.getName() : binding.getName(); 145 } 146 147 @Override 148 public synchronized void addBinding(RestBinding binding) { 149 String key = getBindingKey(binding); 150 bindings.put(key, binding); 151 lookup = null; 152 } 153 154 @Override 155 public synchronized RestBinding removeBinding(RestBinding binding) { 156 RestBinding result = bindings.remove(getBindingKey(binding)); 157 lookup = null; 158 return result; 159 } 160 161 @Override 162 public boolean accept(String name, boolean isChain, HttpServletRequest req) { 163 if (isChain) { 164 name = "Chain." + name; 165 } 166 RestBinding binding = lookup().get(name); 167 if (binding != null) { 168 if (binding.isDisabled()) { 169 return false; 170 } 171 if (binding.isSecure()) { 172 if (!req.isSecure()) { 173 return false; 174 } 175 } 176 Principal principal = req.getUserPrincipal(); 177 178 if (binding.isAdministrator() || binding.hasGroups()) { 179 if (principal instanceof NuxeoPrincipal) { 180 NuxeoPrincipal np = (NuxeoPrincipal) principal; 181 if (binding.isAdministrator() && np.isAdministrator()) { 182 return true; 183 } 184 if (binding.hasGroups()) { 185 for (String group : binding.getGroups()) { 186 if (np.isMemberOf(group)) { 187 return true; 188 } 189 } 190 } 191 } 192 return false; 193 } 194 } 195 return true; 196 } 197 198 private Map<String, RestBinding> lookup() { 199 Map<String, RestBinding> _lookup = lookup; 200 if (_lookup == null) { 201 synchronized (this) { 202 lookup = new HashMap<String, RestBinding>(bindings); 203 _lookup = lookup; 204 } 205 } 206 return _lookup; 207 } 208 209 @Override 210 public List<Class<? extends MessageBodyWriter<?>>> getWriters() { 211 return writers; 212 } 213 214 @Override 215 public List<Class<? extends MessageBodyReader<?>>> getReaders() { 216 return readers; 217 } 218 219}