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