001/* 002 * (C) Copyright 2015-2017 Nuxeo (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 * Vladimir Pasquier <vpasquier@nuxeo.com> 019 */ 020package org.nuxeo.ecm.automation.core; 021 022import java.util.ArrayList; 023import java.util.List; 024 025import javax.management.InstanceAlreadyExistsException; 026import javax.management.InstanceNotFoundException; 027import javax.management.JMException; 028import javax.management.MBeanRegistrationException; 029import javax.management.MBeanServer; 030import javax.management.MalformedObjectNameException; 031import javax.management.NotCompliantMBeanException; 032import javax.management.ObjectName; 033 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036import org.nuxeo.ecm.automation.AutomationAdmin; 037import org.nuxeo.ecm.automation.AutomationFilter; 038import org.nuxeo.ecm.automation.AutomationService; 039import org.nuxeo.ecm.automation.ChainException; 040import org.nuxeo.ecm.automation.OperationException; 041import org.nuxeo.ecm.automation.OperationType; 042import org.nuxeo.ecm.automation.TypeAdapter; 043import org.nuxeo.ecm.automation.context.ContextHelperDescriptor; 044import org.nuxeo.ecm.automation.context.ContextHelperRegistry; 045import org.nuxeo.ecm.automation.context.ContextService; 046import org.nuxeo.ecm.automation.context.ContextServiceImpl; 047import org.nuxeo.ecm.automation.core.events.EventHandler; 048import org.nuxeo.ecm.automation.core.events.EventHandlerRegistry; 049import org.nuxeo.ecm.automation.core.exception.ChainExceptionFilter; 050import org.nuxeo.ecm.automation.core.exception.ChainExceptionImpl; 051import org.nuxeo.ecm.automation.core.impl.ChainTypeImpl; 052import org.nuxeo.ecm.automation.core.impl.OperationServiceImpl; 053import org.nuxeo.ecm.automation.core.trace.TracerFactory; 054import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition; 055import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetDescriptor; 056import org.nuxeo.runtime.api.Framework; 057import org.nuxeo.runtime.management.ServerLocator; 058import org.nuxeo.runtime.model.ComponentContext; 059import org.nuxeo.runtime.model.ComponentInstance; 060import org.nuxeo.runtime.model.DefaultComponent; 061 062/** 063 * Nuxeo component that provide an implementation of the {@link AutomationService} and handle extensions registrations. 064 * 065 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 066 * @author <a href="mailto:grenard@nuxeo.com">Guillaume Renard</a> 067 */ 068public class AutomationComponent extends DefaultComponent { 069 070 private static final Log log = LogFactory.getLog(AutomationComponent.class); 071 072 public static final String XP_OPERATIONS = "operations"; 073 074 public static final String XP_ADAPTERS = "adapters"; 075 076 public static final String XP_CHAINS = "chains"; 077 078 public static final String XP_EVENT_HANDLERS = "event-handlers"; 079 080 public static final String XP_CHAIN_EXCEPTION = "chainException"; 081 082 public static final String XP_AUTOMATION_FILTER = "automationFilter"; 083 084 public static final String XP_CONTEXT_HELPER = "contextHelpers"; 085 086 protected OperationServiceImpl service; 087 088 protected EventHandlerRegistry handlers; 089 090 protected TracerFactory tracerFactory; 091 092 public ContextHelperRegistry contextHelperRegistry; 093 094 protected ContextService contextService; 095 096 public static AutomationComponent self; 097 098 @Override 099 public void activate(ComponentContext context) { 100 service = new OperationServiceImpl(); 101 tracerFactory = new TracerFactory(); 102 handlers = new EventHandlerRegistry(service); 103 self = this; 104 contextService = new ContextServiceImpl(); 105 contextHelperRegistry = new ContextHelperRegistry(); 106 } 107 108 protected void bindManagement() throws JMException { 109 ObjectName objectName = new ObjectName("org.nuxeo.automation:name=tracerfactory"); 110 MBeanServer mBeanServer = Framework.getService(ServerLocator.class).lookupServer(); 111 mBeanServer.registerMBean(tracerFactory, objectName); 112 } 113 114 protected void unBindManagement() throws MalformedObjectNameException, NotCompliantMBeanException, 115 InstanceAlreadyExistsException, MBeanRegistrationException, InstanceNotFoundException { 116 final ObjectName on = new ObjectName("org.nuxeo.automation:name=tracerfactory"); 117 final ServerLocator locator = Framework.getService(ServerLocator.class); 118 if (locator != null) { 119 MBeanServer mBeanServer = locator.lookupServer(); 120 mBeanServer.unregisterMBean(on); 121 } 122 } 123 124 @Override 125 public void deactivate(ComponentContext context) { 126 service = null; 127 handlers = null; 128 tracerFactory = null; 129 } 130 131 @Override 132 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 133 if (XP_OPERATIONS.equals(extensionPoint)) { 134 OperationContribution opc = (OperationContribution) contribution; 135 List<WidgetDefinition> widgetDefinitionList = new ArrayList<>(); 136 if (opc.widgets != null) { 137 for (WidgetDescriptor widgetDescriptor : opc.widgets) { 138 widgetDefinitionList.add(widgetDescriptor.getWidgetDefinition()); 139 } 140 } 141 try { 142 service.putOperation(opc.type, opc.replace, contributor.getName().toString(), widgetDefinitionList); 143 } catch (OperationException e) { 144 throw new RuntimeException(e); 145 } 146 } else if (XP_CHAINS.equals(extensionPoint)) { 147 OperationChainContribution occ = (OperationChainContribution) contribution; 148 // Register the chain 149 try { 150 OperationType docChainType = new ChainTypeImpl(service, 151 occ.toOperationChain(contributor.getContext().getBundle()), occ); 152 service.putOperation(docChainType, occ.replace); 153 } catch (OperationException e) { 154 // TODO Auto-generated catch block 155 throw new RuntimeException(e); 156 } 157 } else if (XP_CHAIN_EXCEPTION.equals(extensionPoint)) { 158 ChainExceptionDescriptor chainExceptionDescriptor = (ChainExceptionDescriptor) contribution; 159 ChainException chainException = new ChainExceptionImpl(chainExceptionDescriptor); 160 service.putChainException(chainException); 161 } else if (XP_AUTOMATION_FILTER.equals(extensionPoint)) { 162 AutomationFilterDescriptor automationFilterDescriptor = (AutomationFilterDescriptor) contribution; 163 ChainExceptionFilter chainExceptionFilter = new ChainExceptionFilter(automationFilterDescriptor); 164 service.putAutomationFilter(chainExceptionFilter); 165 } else if (XP_ADAPTERS.equals(extensionPoint)) { 166 TypeAdapterContribution tac = (TypeAdapterContribution) contribution; 167 TypeAdapter adapter; 168 try { 169 adapter = tac.clazz.newInstance(); 170 } catch (ReflectiveOperationException e) { 171 throw new RuntimeException(e); 172 } 173 service.putTypeAdapter(tac.accept, tac.produce, adapter); 174 } else if (XP_EVENT_HANDLERS.equals(extensionPoint)) { 175 EventHandler eh = (EventHandler) contribution; 176 if (eh.isPostCommit()) { 177 handlers.putPostCommitEventHandler(eh); 178 } else { 179 handlers.putEventHandler(eh); 180 } 181 } else if (XP_CONTEXT_HELPER.equals(extensionPoint)) { 182 contextHelperRegistry.addContribution((ContextHelperDescriptor) 183 contribution); 184 } 185 } 186 187 @Override 188 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 189 if (XP_OPERATIONS.equals(extensionPoint)) { 190 service.removeOperation(((OperationContribution) contribution).type); 191 } else if (XP_CHAINS.equals(extensionPoint)) { 192 OperationChainContribution occ = (OperationChainContribution) contribution; 193 service.removeOperationChain(occ.getId()); 194 } else if (XP_CHAIN_EXCEPTION.equals(extensionPoint)) { 195 ChainExceptionDescriptor chainExceptionDescriptor = (ChainExceptionDescriptor) contribution; 196 ChainException chainException = new ChainExceptionImpl(chainExceptionDescriptor); 197 service.removeExceptionChain(chainException); 198 } else if (XP_AUTOMATION_FILTER.equals(extensionPoint)) { 199 AutomationFilterDescriptor automationFilterDescriptor = (AutomationFilterDescriptor) contribution; 200 AutomationFilter automationFilter = new ChainExceptionFilter(automationFilterDescriptor); 201 service.removeAutomationFilter(automationFilter); 202 } else if (XP_ADAPTERS.equals(extensionPoint)) { 203 TypeAdapterContribution tac = (TypeAdapterContribution) contribution; 204 service.removeTypeAdapter(tac.accept, tac.produce); 205 } else if (XP_EVENT_HANDLERS.equals(extensionPoint)) { 206 EventHandler eh = (EventHandler) contribution; 207 if (eh.isPostCommit()) { 208 handlers.removePostCommitEventHandler(eh); 209 } else { 210 handlers.removeEventHandler(eh); 211 } 212 } else if (XP_CONTEXT_HELPER.equals(extensionPoint)) { 213 contextHelperRegistry.removeContribution( 214 (ContextHelperDescriptor) contribution); 215 } 216 } 217 218 @Override 219 public <T> T getAdapter(Class<T> adapter) { 220 if (adapter == AutomationService.class || adapter == AutomationAdmin.class) { 221 return adapter.cast(service); 222 } 223 if (adapter == EventHandlerRegistry.class) { 224 return adapter.cast(handlers); 225 } 226 if (adapter == TracerFactory.class) { 227 return adapter.cast(tracerFactory); 228 } 229 if (adapter == ContextService.class) { 230 return adapter.cast(contextService); 231 } 232 return null; 233 } 234 235 @Override 236 public void start(ComponentContext context) { 237 if (!tracerFactory.getRecordingState()) { 238 log.info("You can activate automation trace mode to get more informations on automation executions"); 239 } 240 try { 241 bindManagement(); 242 } catch (JMException e) { 243 throw new RuntimeException("Cannot bind management", e); 244 } 245 } 246 247 @Override 248 public void stop(ComponentContext context) { 249 service.flushCompiledChains(); 250 try { 251 unBindManagement(); 252 } catch (JMException e) { 253 throw new RuntimeException("Cannot unbind management", e); 254 } 255 } 256}