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 <[email protected]> 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:[email protected]">Bogdan Stefanescu</a> 066 * @author <a href="mailto:[email protected]">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 protected ContextHelperRegistry contextHelperRegistry; 093 094 protected ContextService contextService; 095 096 @Override 097 public void activate(ComponentContext context) { 098 service = new OperationServiceImpl(); 099 tracerFactory = new TracerFactory(); 100 handlers = new EventHandlerRegistry(service); 101 contextHelperRegistry = new ContextHelperRegistry(); 102 contextService = new ContextServiceImpl(contextHelperRegistry); 103 } 104 105 protected void bindManagement() throws JMException { 106 ObjectName objectName = new ObjectName("org.nuxeo.automation:name=tracerfactory"); 107 MBeanServer mBeanServer = Framework.getService(ServerLocator.class).lookupServer(); 108 mBeanServer.registerMBean(tracerFactory, objectName); 109 } 110 111 protected void unBindManagement() throws MalformedObjectNameException, NotCompliantMBeanException, 112 InstanceAlreadyExistsException, MBeanRegistrationException, InstanceNotFoundException { 113 final ObjectName on = new ObjectName("org.nuxeo.automation:name=tracerfactory"); 114 final ServerLocator locator = Framework.getService(ServerLocator.class); 115 if (locator != null) { 116 MBeanServer mBeanServer = locator.lookupServer(); 117 mBeanServer.unregisterMBean(on); 118 } 119 } 120 121 @Override 122 public void deactivate(ComponentContext context) { 123 service = null; 124 handlers = null; 125 tracerFactory = null; 126 } 127 128 @Override 129 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 130 if (XP_OPERATIONS.equals(extensionPoint)) { 131 OperationContribution opc = (OperationContribution) contribution; 132 List<WidgetDefinition> widgetDefinitionList = new ArrayList<>(); 133 if (opc.widgets != null) { 134 for (WidgetDescriptor widgetDescriptor : opc.widgets) { 135 widgetDefinitionList.add(widgetDescriptor.getWidgetDefinition()); 136 } 137 } 138 try { 139 service.putOperation(opc.type, opc.replace, contributor.getName().toString(), widgetDefinitionList); 140 } catch (OperationException e) { 141 throw new RuntimeException(e); 142 } 143 } else if (XP_CHAINS.equals(extensionPoint)) { 144 OperationChainContribution occ = (OperationChainContribution) contribution; 145 // Register the chain 146 try { 147 OperationType docChainType = new ChainTypeImpl(service, 148 occ.toOperationChain(contributor.getContext().getBundle()), occ); 149 service.putOperation(docChainType, occ.replace); 150 } catch (OperationException e) { 151 // TODO Auto-generated catch block 152 throw new RuntimeException(e); 153 } 154 } else if (XP_CHAIN_EXCEPTION.equals(extensionPoint)) { 155 ChainExceptionDescriptor chainExceptionDescriptor = (ChainExceptionDescriptor) contribution; 156 ChainException chainException = new ChainExceptionImpl(chainExceptionDescriptor); 157 service.putChainException(chainException); 158 } else if (XP_AUTOMATION_FILTER.equals(extensionPoint)) { 159 AutomationFilterDescriptor automationFilterDescriptor = (AutomationFilterDescriptor) contribution; 160 ChainExceptionFilter chainExceptionFilter = new ChainExceptionFilter(automationFilterDescriptor); 161 service.putAutomationFilter(chainExceptionFilter); 162 } else if (XP_ADAPTERS.equals(extensionPoint)) { 163 TypeAdapterContribution tac = (TypeAdapterContribution) contribution; 164 TypeAdapter adapter; 165 try { 166 adapter = tac.clazz.newInstance(); 167 } catch (ReflectiveOperationException e) { 168 throw new RuntimeException(e); 169 } 170 service.putTypeAdapter(tac.accept, tac.produce, adapter); 171 } else if (XP_EVENT_HANDLERS.equals(extensionPoint)) { 172 EventHandler eh = (EventHandler) contribution; 173 if (eh.isPostCommit()) { 174 handlers.putPostCommitEventHandler(eh); 175 } else { 176 handlers.putEventHandler(eh); 177 } 178 } else if (XP_CONTEXT_HELPER.equals(extensionPoint)) { 179 contextHelperRegistry.addContribution((ContextHelperDescriptor) 180 contribution); 181 } 182 } 183 184 @Override 185 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 186 if (XP_OPERATIONS.equals(extensionPoint)) { 187 service.removeOperation(((OperationContribution) contribution).type); 188 } else if (XP_CHAINS.equals(extensionPoint)) { 189 OperationChainContribution occ = (OperationChainContribution) contribution; 190 service.removeOperationChain(occ.getId()); 191 } else if (XP_CHAIN_EXCEPTION.equals(extensionPoint)) { 192 ChainExceptionDescriptor chainExceptionDescriptor = (ChainExceptionDescriptor) contribution; 193 ChainException chainException = new ChainExceptionImpl(chainExceptionDescriptor); 194 service.removeExceptionChain(chainException); 195 } else if (XP_AUTOMATION_FILTER.equals(extensionPoint)) { 196 AutomationFilterDescriptor automationFilterDescriptor = (AutomationFilterDescriptor) contribution; 197 AutomationFilter automationFilter = new ChainExceptionFilter(automationFilterDescriptor); 198 service.removeAutomationFilter(automationFilter); 199 } else if (XP_ADAPTERS.equals(extensionPoint)) { 200 TypeAdapterContribution tac = (TypeAdapterContribution) contribution; 201 service.removeTypeAdapter(tac.accept, tac.produce); 202 } else if (XP_EVENT_HANDLERS.equals(extensionPoint)) { 203 EventHandler eh = (EventHandler) contribution; 204 if (eh.isPostCommit()) { 205 handlers.removePostCommitEventHandler(eh); 206 } else { 207 handlers.removeEventHandler(eh); 208 } 209 } else if (XP_CONTEXT_HELPER.equals(extensionPoint)) { 210 contextHelperRegistry.removeContribution( 211 (ContextHelperDescriptor) contribution); 212 } 213 } 214 215 @Override 216 public <T> T getAdapter(Class<T> adapter) { 217 if (adapter == AutomationService.class || adapter == AutomationAdmin.class) { 218 return adapter.cast(service); 219 } 220 if (adapter == EventHandlerRegistry.class) { 221 return adapter.cast(handlers); 222 } 223 if (adapter == TracerFactory.class) { 224 return adapter.cast(tracerFactory); 225 } 226 if (adapter == ContextService.class) { 227 return adapter.cast(contextService); 228 } 229 return null; 230 } 231 232 @Override 233 public void start(ComponentContext context) { 234 if (!tracerFactory.getRecordingState()) { 235 log.info("You can activate automation trace mode to get more informations on automation executions"); 236 } 237 try { 238 bindManagement(); 239 } catch (JMException e) { 240 throw new RuntimeException("Cannot bind management", e); 241 } 242 } 243 244 @Override 245 public void stop(ComponentContext context) { 246 service.flushCompiledChains(); 247 try { 248 unBindManagement(); 249 } catch (JMException e) { 250 throw new RuntimeException("Cannot unbind management", e); 251 } 252 } 253}