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