DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.

DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
...
| Code Block |
|---|
public abstract class BaseCmd {
static public ConfigurationService _configService;
static public AccountService _accountService;
static public UserVmService _userVmService;
static public ManagementService _mgr;
// more code ...
// code to resolve above static references using runtime resolution
}
|
...
| Code Block |
|---|
public class ConfigurationDaoImpl extends GenericDaoBase<ConfigurationVO, String> implements ConfigurationDao {
@PostConstruct @PostConstruct void initComponent() { // more code... }
}
|
...
Although we've tried the best to cut the relationship to a component container inside component code, we still have very few places in framework components that need to be aware of existence of the component container, to avoid any strong binding to a particular container like Spring, we introduced a class called ComponentContext, it is responsible to bridge CloudStack component with a chosen component container (for now, it is Spring).
As a business logic component developer, you should avoid using any of the functions provided by ComponentContext, this can make the business component neutral to component container, since we use standard javax @Inject auto-wiring mechanism, it is even possible for your component to run in containers that are other than CloudStack.
limit direct use of ComponentContext with one exception: using ComponentContext.inject() to auto-wire components. Following example gives a scenario.
| Code Block |
|---|
Class<?> cmdClass = getCmdClass(command[0]);
if (cmdClass != null) {
BaseCmd cmdObj = (BaseCmd) cmdClass.newInstance();
cmdObj = ComponentContext.inject(cmdObj);
cmdObj.configure();
cmdObj.setFullUrlParams(paramMap);
cmdObj.setResponseType(responseType);
...
}
public class FooCmd {
@Inject FooService _fooService;
@Inject GeniusService _geniusService;
....
}
|
cmdObj = ComponentContext.inject(cmdObj);
Above one-line enabler makes it possible to use @Inject pattern in all CloudStack command classes consistently across the board. Spring will automatically wire the object in reference for the newly constructed object at run-time. If you have to use run-time constructed objects and have cases to pass over a set of service objects, instead of using pattern like
| Code Block |
|---|
public class FooObject {
FooService _fooService;
public FooObject(FooService service) {
_fooService = service;
}
....
}
|
You may take advantage of auto-wiring as
| Code Block |
|---|
public class FooObject {
@Inject FooService _fooService;
public FooObject() {
}
...
} |
If you see yourself constantly need to pass a lot of service objects to a object constructor (or setters), use ComponentContext.inject() to help you out.
We found that outWe found that out-of-box AOP offering from Spring does not work with CloudStack, Spring AOP uses proxy mechanism, it can only intercept method calls that are "calling into" the component through a generated proxy object, unfortunately some of CloudStack codebase relies on the fact that method interception should happen for inner method calls within the component class itself. To solve this problem, we have to develop a customized AOP under Spring. Following is an example of such use case.
| Code Block |
|---|
package com.cloud.event;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
import com.cloud.user.UserContext;
import com.cloud.utils.component.ComponentMethodInterceptor;
public class ActionEventInterceptor implements ComponentMethodInterceptor {
private static final Logger s_logger = Logger.getLogger(ActionEventInterceptor.class);
public ActionEventInterceptor() {
}
@Override
public Object interceptStart(Method method, Object target) {
EventVO event = null;
ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
if (actionEvent != null) {
boolean async = actionEvent.async();
if(async){
UserContext ctx = UserContext.current();
long userId = ctx.getCallerUserId();
long accountId = ctx.getAccountId();
long startEventId = ctx.getStartEventId();
String eventDescription = actionEvent.eventDescription();
if(ctx.getEventDetails() != null){
eventDescription += ". "+ctx.getEventDetails();
}
EventUtils.saveStartedEvent(userId, accountId, actionEvent.eventType(), eventDescription, startEventId);
}
}
return event;
}
@Override
public void interceptComplete(Method method, Object target, Object event) {
ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);
if (actionEvent != null) {
UserContext ctx = UserContext.current();
long userId = ctx.getCallerUserId();
long accountId = ctx.getAccountId();
long startEventId = ctx.getStartEventId();
String eventDescription = actionEvent.eventDescription();();
if(ctx.getEventDetails() != null){
eventDescription += ". "+ctx.getEventDetails();
}
if(ctxactionEvent.getEventDetailscreate() != null){
//This eventDescription += ". "+ctx.getEventDetails();
start event has to be used for subsequent events of this action
}
startEventId = EventUtils.saveCreatedEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully created entity if(actionEvent.create()){for "+eventDescription);
//This start event has to be used for subsequent events of this action
ctx.setStartEventId(startEventId);
} else {
startEventId = EventUtils.saveCreatedEventsaveEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully completed "+eventDescription, "Successfully created entity for "+eventDescription); startEventId);
}
}
}
@Override
public void interceptException(Method method, Object target, Object ctx.setStartEventId(startEventId);event) {
ActionEvent actionEvent = } else {
method.getAnnotation(ActionEvent.class);
if (actionEvent != null) {
EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully completed "+eventDescription, startEventId UserContext ctx = UserContext.current();
}
long userId = ctx.getCallerUserId();
}
long accountId }
= ctx.getAccountId();
@Override
public void interceptException(Method method, Objectlong target,startEventId Object event) {
= ctx.getStartEventId();
ActionEventString actionEventeventDescription = methodactionEvent.getAnnotationeventDescription(ActionEvent.class);
if (actionEvent if(ctx.getEventDetails() != null) {
UserContext ctxeventDescription += UserContext.current ". "+ctx.getEventDetails();
}
long userId = ctx.getCallerUserId();
if(actionEvent.create()){
long eventId = EventUtils.saveCreatedEvent(userId, accountId = ctx.getAccountId();
long startEventId = ctx.getStartEventId();
, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while creating entity for "+eventDescription);
String eventDescription = actionEventctx.eventDescriptionsetStartEventId(eventId);
if(ctx.getEventDetails() != null)} else {
EventUtils.saveEvent(userId, eventDescription += ". "+ctx.getEventDetails(accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while "+eventDescription, startEventId);
}
}
if(actionEvent.create()){}
@Override
public boolean needToIntercept(Method method) {
longActionEvent eventIdactionEvent = EventUtilsmethod.saveCreatedEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while creating entity for "+eventDescription);
getAnnotation(ActionEvent.class);
if (actionEvent != null) {
ctx.setStartEventId(eventId)return true;
} else {
return false;
EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while "+eventDescription, startEventId);
}
}
}
@Override
public boolean needToIntercept(Method method) {}
}
|
If you ever need to implement a method interceptor, implement interface ComponentMethodInterceptor and declare it in applicationContext.xml.in. As you see in the above example, ActionEventInterceptor implements an aspect to automatically log events at methods in classes that have been marked as @ActionEvent. To install such interceptor, declare it as following in applicationContext.xml.in
| Code Block |
|---|
<bean id="actionEventInterceptor" class="com.cloud.event.ActionEventInterceptor" /> <bean id="instantiatePostProcessor" class="com.cloud.utils.component.ComponentInstantiationPostProcessor"> <property name="Interceptors"> ActionEvent<list> actionEvent = method.getAnnotation(ActionEvent.class); if (actionEvent<ref !bean= null) {"transactionContextBuilder" /> return true; <ref bean="actionEventInterceptor" /> }</list> </property> return false; } } |
If you ever need to implement a method interceptor, implement interface ComponentMethodInterceptor and declare it in applicationContext.xml.in.
...
</bean>
|
Not any class can be intercepted in this way, both due to implementation limitation and for sake of performance, only classes that have marked itself with a marker interface ComponentMethodInterceptable can be intercepted to apply above AOP pattern. All Manager, Adapter and DAO classes are currently marked with ComponentMethodInterceptable.
ComponentInstantiationPostProcessor is a CloudStack implemented Spring post processor that eventually implements the Customized AOP pattern. ComponentInstantiationPostProcessor uses CGLIB to replace loaded component instance with a CGLIB generated wrapper object that is a sub-class instance of the original object, in this way, it can provide hooks to all method calls to the object through ComponentMethodInterceptor.
The sub-class generated by CGLIB uses the naming convention implemented in ComponentNamingPolicy. All these generated classes are named after "EnhancedByCloudStack" pattern, you may notice it in log messages or in debug session.
...
Adapter components usually works under the management of its manager component, a same set of adapter components may be used by multiple managers, and sometimes, order of the adapters may also be significant. Whether or not an adapter component is in action depends not only the existence of its <bean> declaration, but also the references in manager components.
...