I have asked a question here but I did not get an answer. Howerver, I continue my search and I found something which could please my need : "MBeanServerForwarder". I read the official JavaDoc but it is still not clear for me.
So, does MBeanServerForwarder work as a proxy for a MBeanServer? ie: Can I use it to intercept MBeans registry, make modification in the ObjectName and forward it to the MBeanServer?
Thanks in advance.
Yes, but it's not really necessary. You only need to implement the MBeanServer interface and override the registerMBean method (and perhaps the unregisterMBean method).
Using the real MBeanServer as a delegate, here's what your implementation might look like:
public class AltObjectNameMBeanServer implements MBeanServer {
protected final MBeanServer innerServer;
protected final ObjectName filter;
public AltObjectNameMBeanServer(MBeanServer innerServer, ObjectName filter) {
this.innerServer = innerServer;
this.filter = filter;
}
public ObjectInstance registerMBean(Object object, ObjectName name) throws InstanceAlreadyExistsException,
MBeanRegistrationException, NotCompliantMBeanException {
if(filter.apply(name)) {
name = reformat(name);
}
return innerServer.registerMBean(object, name);
}
public static ObjectName reformat(ObjectName on)
try {
int id = on.toString().hashCode();
return new ObjectName(new StringBuilder(on.toString()).append(",serial=").append(id).toString());
} catch (Exception e) {
throw new RuntimeException("Failed to reformat [" + on + "]", e);
}
}
// ======== Put direct delegates for all other methods =======
}
Sample usage:
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
AltObjectNameMBeanServer rr = new AltObjectNameMBeanServer(server, new ObjectName("*:*"));
Class clazz = Class.forName("sun.management.HotspotInternal");
HotspotInternalMBean obj = (HotspotInternal)clazz.newInstance();
ObjectInstance oi = rr.registerMBean(new StandardMBean(obj, HotspotInternalMBean.class), new javax.management.ObjectName("sun.management:type=HotspotInternal"));
System.out.println("ObjectName:" + oi.getObjectName());
The output is:
ObjectName:sun.management:type=HotspotInternal,serial=-441253090
With a bit of reflection, you could set your new MBeanServer impl. in the platformMBeanServer field of the java.lang.management.ManagementFactory and you will have permanently overriden the JVM agent's MBean registration.
========== Update ============
This code snippet demonstrates how you might hack the platform MBeanServer to supply an alternate (or wrapped) MBeanServer (using the rr instance of AltObjectNameMBeanServer from above:
Field serverField = ManagementFactory.class.getDeclaredField("platformMBeanServer");
serverField.setAccessible(true);
serverField.set(null, rr);
System.out.println("Equal:" + (rr==ManagementFactory.getPlatformMBeanServer()));
========== Update ============
Here's a simple example of what I think you are looking for.
See this gist.
If you run the example with these options:
-Djavax.management.builder.initial=org.helios.jmx.HeliosMBeanServerBuilder
-Dhelios.jmx.renamer.filter=java.util.logging:*
It will override the system's default MBeanServerBuilder and intercept all MBean registrations with ObjectNames matching java.util.logging:*.
When the main runs, it will print all the platform MBeanServer MBean ObjectNames and the output will look like this:
MBeanServer Interceptor Test
java.lang:type=MemoryPool,name=PS Eden Space
java.lang:type=Memory
java.lang:type=MemoryPool,name=PS Survivor Space
java.lang:type=GarbageCollector,name=PS MarkSweep
java.lang:type=MemoryPool,name=Code Cache
java.lang:type=Runtime
java.lang:type=ClassLoading
java.lang:type=Threading
java.lang:type=Compilation
com.sun.management:type=HotSpotDiagnostic
java.lang:type=MemoryPool,name=PS Perm Gen
java.util.logging:type=Logging,serial=-132046985
java.lang:type=OperatingSystem
java.lang:type=GarbageCollector,name=PS Scavenge
java.lang:type=MemoryPool,name=PS Old Gen
java.lang:type=MemoryManager,name=CodeCacheManager
JMImplementation:type=MBeanServerDelegate
Note the renaming of java.util.logging:type=Logging,serial=-132046985
Alternatively, you can create your own instance of the HeliosMBeanServer builder, define the domain name, the filter and the rename strategy and create your own MBeanServer rather than using the platform MBeanServer.
Thanks to Nicholas.
MBeans registration interception
I used a Proxy to intercept all calls to BeanServer with Invocation Handler and Invocation Context. I used several interceptors to edit parameters (registerMBean parameters for example) before invoking the method and it works.
Set MBeanServer as platformMBeanServer
Nicholas's method (see his post)
Use customized MBeanServerBuilder
For that, we have to set a system property :
-Djavax.management.builder.initial=my.own.MBeanServerBuilder
You will probably get an NotFoundClassException. To deal with this, ensure that the classloader of Thread.CurrentThread() is the same than the class which create the MBeanServer.
Your own MBeanServerBuilder must extend MBeanServerBuilder class. Depending in your needs, override method to add information. For my use case, I had to return a proxy of the MBeanServer, so I create a new MBeanServer, create the proxy and return it.
public MBeanServer newMBeanServer(String defaultDomain,
MBeanServer outer,
MBeanServerDelegate delegate) {
MBeanServer origin = super.newMBeanServer(defaultDomain, outer, delegate);
return (MBeanServer) Proxy.newProxyInstance(origin.getClass().getClassLoader(), new Class<?>[]{MBeanServer.class}, handler);
}
Related
Here's what I'm doing so far (code simplified):
public class MyRegistrationSource : IRegistrationSource
{
public MyRegistrationSource(ContainerBuilder builder /*,...*/)
{
// ...
this.builder = builder;
}
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
// Some checks here
var interfaceType = serviceWithType.ServiceType;
var implementorType = FindTheRightImplementor(interfaceType);
if (myRegisterConditionSatisfied)
{
return Register(implementorType, interfaceType);
}
return Empty;
}
private IEnumerable<IComponentRegistration> Register(Type concrete, Type #interface)
{
var regBuilder = builder.RegisterType(concrete).As(#interface).IfNotRegistered(#interface);
return new[] { regBuilder.CreateRegistration() };
}
}
Then, at startup I'm doing something like
builder.RegisterSource(
new NonRegisteredServicesRegistrationSource(builder/*, ...*/));
The above is intended to register those matching services only when there's no previous registration. I tried doing the registration without using the ContainerBuilder but couldn't get it to work.
This is working but are there any issues in passing-in the ContainerBuilder instance to the RegistrationSource?
Thanks!
I'd probably argue against passing in a ContainerBuilder.
Every type you register in your source will add a callback to a list of callbacks inside the Container Builder which will never get cleared, potentially creating a memory leak.
I'd suggest calling the static method RegistrationBuilder.ForType instead, which will give you a fluent builder and should let you subsequently call CreateRegistration as you are now.
You can see some pretty good examples of how do this in our Moq integration:
var reg = RegistrationBuilder.ForType(concrete)
.As(#interface)
.CreateRegistration();
Also, I don't believe IfNotRegistered will have any effect when used outside the context of a ContainerBuilder. You should use the provided registrationAccessor parameter to the registration source to look up a TypedService to see if it has already been registered:
var isRegistered = registrationAccessor(new TypedService(#interface)).Any();
Lets say I have a factory returning different classes via methods.
class CarFactory
{
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function createCarOne() : CarInterface
{
return $this->container->make(CarOneClass::class);
}
// Vs
public function createCarTwo() : CarInterface
{
return new CarTwoClass({Inject Dependencies Here});
}
}
When would this be considered a service locator or anti-pattern and why? I am considering the first method solely for the dependency resolution provided by the container. All car's have the same typed interface dependencies the main difference of the entities come from how they transform the data provided.
Whenever one of these methods are called I need a new instance of the specified car so the data set can be transformed based on the choice.
This is not the implementation but the easiest example I can provide.
$output = [];
foreach ($car as $key => $data) {
$newCar = $this->factory->createCar{$key}();
// Pass Some Data To The New Car Methods So It Can Be Transformed
$output[] = $newCar;
}
return $output;
If this is the wrong approach what would be the alternative option?
Edit
After further digging I see some IoC containers pass factory callables as dependencies. I was going to bind each Car to a callable but thanks to the ability to type hint data from method returns (php7) I can configure factories using a provider then call the 'callable factory' from within the CarFactory. Requires additional binding but prevents the need to reference/dependency inject the IoC container within every factory.
Still researching I would love to hear feedback from those with more experience.
Ex:
// Within Some Registered Provider
// I Will Have To Wire Each Car
$one = function() use ($app) {
return $app->make(CarOne::class);
};
$two = function() use ($app) {
return $app->make(CarTwo::class);
};
$app->bind(ICarFactory::class, function($app) use ($one, $two) {
return $app->make($concrete, [$one, $two]);
});
// Car Factory Constructor
public function __construct(callable $carOne, callable $carTwo) {
$this->one = $carOne;
$this->two = $carTwo;
}
Since get methods are type hinted ( view original car factory ) an error is thrown when the returned item does not implement CarInterface, each factory method would just have to call the 'callable factory' ( something like this return ($this->one)();).
I believe i solve my problem of outsourcing creation of dependencies ( avoiding creating within factory was bothering the hell out of me ) while still following 'best practices'. Still looking for advice if anyone has any to offer.
I need to call DAO methods outside resource in dropwizard.
Looking at the manual Im unclear how to use it. The manual says
SessionDao dao = new SessionDao(hibernateBundle.getSessionFactory());
ExampleAuthenticator exampleAuthenticator = new
UnitOfWorkAwareProxyFactory(hibernateBundle)
.create(ExampleAuthenticator.class, SessionDao.class, dao);
Can anyone show me the usage of exampleAuthenticator methods which call DAO.
Thanks, Kedar
Working solution
/** initializing proxy dao for authorization */
AuthenticatorDAOProxy authenticatorDAOProxy = new UnitOfWorkAwareProxyFactory(hibernateBundle)
.create(AuthenticatorDAOProxy.class, DeviceDAO.class, deviceDAO);
We can now use authenticatorDAOProxy outside jersey resources
One thing to note., AuthenticatorDAOProxy should have a constructor accepting DeviceDAO
Now your proxyDao will look like
public class AuthenticatorDAOProxy {
private DeviceDAO deviceDAO;
public AuthenticatorDAOProxy(DeviceDAO deviceDAO) {
this.deviceDAO = deviceDAO;
}
#UnitOfWork
public Boolean checkIsDeviceValid(String deviceId, User user) {
Device device = deviceDAO.getByDeviceIdAndUser(deviceId, user);
if (device != null && device.getIsActive() == true) {
return true;
}
return false;
}
}
Each Dropwizard module have a testsuite. Here is the answer you are looking for: https://github.com/dropwizard/dropwizard/blob/release/1.1.x/dropwizard-hibernate/src/test/java/io/dropwizard/hibernate/UnitOfWorkAwareProxyFactoryTest.java#L121-L151
The logic is:
The DAO object instance holds a reference to the Hibernate SessionFactory;
A method that access the DB calls sessionFactory.getCurrentSession(). The sample code is executing a native query and returns true if at least one result row is returned from the DB;
The OAuthAuthenticator instance holds a reference to the DAO instance and calls the appropriate method of the DAO.
The test case is here: https://github.com/dropwizard/dropwizard/blob/release/1.1.x/dropwizard-hibernate/src/test/java/io/dropwizard/hibernate/UnitOfWorkAwareProxyFactoryTest.java#L64-L74
Our company has the need to log certain things each time one of our action methods of our ASP.NET WebApi controllers gets called. Since we use Ninject for the DI right now, we'd like to use it also for this purpose. This is what I have tried so far.
I have Ninject, Ninject.Extensions.Interception and Ninject.Extensions.Interception.DynamicProxy installed through NuGet and I have the following module
public class InterceptAllModule : InterceptionModule
{
public override void Load()
{
Kernel.Intercept(p => p.Request.Service.Name.EndsWith("Controller")).With(new TimingInterceptor());
}
}
Where TimingInterceptor is
public class TimingInterceptor : SimpleInterceptor
{
readonly Stopwatch _stopwatch = new Stopwatch();
protected override void BeforeInvoke(IInvocation invocation)
{
_stopwatch.Start();
}
protected override void AfterInvoke(IInvocation invocation)
{
_stopwatch.Stop();
string message = string.Format("[Execution of {0} took {1}.]",invocation.Request.Method,_stopwatch.Elapsed);
Log.Info(message + "\n");
_stopwatch.Reset();
}
}
Now, when I try to hook the module up with ninject kernel, and run my site
var kernel = new StandardKernel(new InterceptAllModule());
However, whenever there is a call coming in to one of the action method, it throws an error saying
Cannot instantiate proxy of class: MyApiController.
Could someone with experience point out what I'm doing wrong please? Thanks.
Update
So using your Code and Remo's excellent point about needing the action methods to be virtual and putting in an empty default constructor (just to placate dynamic proxy, keep your other constructor still) I have got both the action filter and the interception approach working.
I would say that as it stands your code will intercept potentially unwanted methods on the ApiController so you will probably also need to put some code in place to filter these out e.g. ExecuteAsync and Dispose.
My only other point is performance. Huge disclaimer these are just very basic tests (using the action filter approach each time to log the stats), I invite you to do your own(!)... but using the DynamicProxy interceptor I was getting a time of around 4 milliseconds per get request
[Execution of Get took 00:00:00.0046615.]
[Execution of Get took 00:00:00.0041988.]
[Execution of Get took 00:00:00.0039383.]
Commenting out the Interception code and using an Action filter I was getting sub millisecond performance:
[Execution of Get took 00:00:00.0001146.]
[Execution of Get took 00:00:00.0001116.]
[Execution of Get took 00:00:00.0001364.]
It is up to you whether this is actually an issue or concern but I thought I would point this out.
Previous Response
Have you rulled out using ActionFilters? This is the natural extension point for AOP on an MVC action.
If you were interested in methods other than the actual action on the controller then I would understand but I thought I would post a suggestion anyway.
Inspired by Are ActionFilterAttributes reused across threads? How does that work? and Measure Time Invoking ASP.NET MVC Controller Actions.
Updated to show the exclusion of the timer when method tagged. Inspiration from core WebApi framework specifically AllowAnonymousAttribute and AuthorizeAttribute
Register this globally so that all actions are monitored by this:
GlobalConfiguration.Configuration.Filters.Add(new TimingActionFilter());
Then:
public class TimingActionFilter : ActionFilterAttribute
{
private const string Key = "__action_duration__";
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (SkipLogging(actionContext))
{
return;
}
var stopWatch = new Stopwatch();
actionContext.Request.Properties[Key] = stopWatch;
stopWatch.Start();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (!actionExecutedContext.Request.Properties.ContainsKey(Key))
{
return;
}
var stopWatch = actionExecutedContext.Request.Properties[Key] as Stopwatch;
if(stopWatch != null)
{
stopWatch.Stop();
var actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;
Debug.Print(string.Format("[Execution of {0} took {1}.]", actionName, stopWatch.Elapsed));
}
}
private static bool SkipLogging(HttpActionContext actionContext)
{
return actionContext.ActionDescriptor.GetCustomAttributes<NoLogAttribute>().Any() ||
actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<NoLogAttribute>().Any();
}
}
And
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public class NoLogAttribute : Attribute
{
}
Now you can exclude the global filter using:
public class ExampleController : ApiController
{
// GET api/example
[NoLog]
public Example Get()
{
//
}
}
For anyone still lurking, the reason I wanted to use Ninject was so I could inject a logger (or anything else) into the interceptor, but I wanted to intercept all actions.
Mark's answer is perfect, but instead of registering globally using
GlobalConfiguration.Configuration.Filters.Add(new TimingActionFilter());
bind your filter with Ninject using
Kernal.BindHttpFilter<TimingActionFilter>(FilterScope.Action).
You'll need to create an appropriate contructor in the TimingActionFilter class.
Becuase monotouch compile to native code, so it has some limitation such as dynamic invoke is not allowed.
But I have a lot class in .net, that I use the ChannelFactory dynamic to invoke the wcf service: new ChannelFactory(myBinding, myEndpoint); Now in monotouch I should use the slsvcutil to generate the wcf proxy class, but the slsvcutil generate a lot of Unnecessary extra code (huge), and Makes consumers difficult to unit test, due to high coupling with the WCF infrastructure through the ClientBase class.
Is there a better solution except the ChannelFactory? I would rather write the code manually, have more control over how services are invoked such as the ChannelFactory.
==========
ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>(binding, endpointAddress);
return factory.CreateChannel();
//==> It throw exception: MonoTouch does not support dynamic proxy code generation. Override this method or its caller to return specific client proxy instance
ChannelFactory<T> has a virtual method CreateChannel(). If this is not overridden, it uses dynamic code generation, which fails on MonoTouch.
The solution is to override it and provide your own compile-time implementation.
Below is an old service implementation of mine that at least used to work on MonoTouch. I split it up into 2 partial classes - the first one being linked in all builds, the 2nd only in the iOS builds (allowing the dynamic generation mechanism to still work on windows).
I've stripped it down to only contain 1 service call.
TransactionService.cs:
public partial class TransactionService : ClientBase<IConsumerService>, IConsumerService
{
public TransactionService()
{
}
public TransactionService(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public TransactionService(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public TransactionService(string endpointConfigurationName, EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public TransactionService(Binding binding, EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
public AccountBalanceResponse GetAccountBalance( AccountBalanceQuery query )
{
return Channel.GetAccountBalance( query );
}
}
TransactionService.iOS.cs:
ConsumerServiceClientChannel which executes the calls via reflection)
public partial class TransactionService
{
protected override IConsumerService CreateChannel()
{
return new ConsumerServiceClientChannel(this);
}
private class ConsumerServiceClientChannel : ChannelBase<IConsumerService>, IConsumerService
{
public ConsumerServiceClientChannel(System.ServiceModel.ClientBase<IConsumerService> client) :
base(client)
{
}
// Sync version
public AccountBalanceResponse GetAccountBalance(AccountBalanceQuery query)
{
object[] _args = new object[1];
_args[0] = query;
return (AccountBalanceResponse)base.Invoke("GetAccountBalance", _args);
}
// Async version
public IAsyncResult BeginGetAccountBalance(AccountBalanceQuery query, AsyncCallback callback, object asyncState )
{
object[] _args = new object[1];
_args[0] = query;
return (IAsyncResult)base.BeginInvoke("GetAccountBalance", _args, callback, asyncState );
}
public AccountBalanceResponse EndGetAccountBalance(IAsyncResult asyncResult)
{
object[] _args = new object[0];
return (AccountBalanceResponse)base.EndInvoke("GetAccountBalance", _args, asyncResult);
}
}
}
EDIT: I just tested this with the latest MT (5.2) - it no longer needs all that extra boiler plate I had in there before, just the CreateChannel() override. I've cleaned up the sample code to match.
EDIT2: I added an async method implementation.
I think you might be confusing terms here - ChannelFactory is a generic type, not a dynamic.
According to MonoTouch documentation, although there's limitations to the Generics support in MonoTouch, ChannelFactory should be okay here.
Have you tried using ChannelFactory?