I'd like to publish JMX notifications using Spring 3, but would like to avoid using the NotificationPublisherAware interface, since the code is also used by an application that doesn't use Spring. The bean is exposed using MBeanExporter bean. The alternatives I found require registering the mbeans, which I currently do using Spring configuration, so this is a bad option.
Is there a way to avoid using the NotificationPublisherAware interface but still publish notifications?
You don't have to use any Spring class in code. Example:
Interface:
import javax.management.MXBean;
#MXBean
public interface SecurityEventsManagerMXBean {
...
#AttributeMetaData(value="UserLoginFailures", defaultValue="0", description="Total user login failures")
public int getUserLoginFailureCount() ;
...
}
Bean:
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
public class SecurityEventsManager extends NotificationBroadcasterSupport implements SecurityEventsManagerMXBean {
...
private void notifyUserLoginFailure(...) {
Notification notification = new Notification(...) ;
sendNotification(notification)
userLoginFailureCount++ ;
}
}
Here #AttributeMetaData is a convenient meta annotation that defines descriptor keys:
import javax.management.DescriptorKey;
#Documented
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface AttributeMetaData {
#DescriptorKey("displayName")
String value();
....
}
Edit March 08. Configuration to export above Mbean:
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"
p:locateExistingServerIfPossible="true" />
<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
<bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy"
p:attributeSource-ref="jmxAttributeSource" />
<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"
p:attributeSource-ref="jmxAttributeSource" />
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="server" ref="mbeanServer"/>
<property name="assembler" ref="assembler"/>
<property name="registrationBehaviorName" value="REGISTRATION_FAIL_ON_EXISTING"/>
<property name="beans">
<map>
<entry>
<key>
<util:constant
static-field="x.y.z.SecurityEventsManager.OBJECT_NAME" />
</key>
<ref bean="securityEventsManager" />
</entry>
</map>
</property>
</bean>
<bean id="securityEventsManager" class="x.y.z.SecurityEventsManager" />
As per Spring docs:
The NotificationPublisher interface and the machinery to get it all working is one of the nicer features of Spring's JMX support. It does however come with the price tag of coupling your classes to both Spring and JMX; as always, the advice here is to be pragmatic... if you need the functionality offered by the NotificationPublisher and you can accept the coupling to both Spring and JMX, then do so.
Ref: http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch24s07.html#jmx-notifications-listeners
Related
I am refering to Spring AOP by Mkyong http://www.mkyong.com/spring/spring-aop-example-pointcut-advisor/
It worked when tried running from main (i.e. App.java) as given on above link,
I want to integrate it in restful webservice where i have multiple service like CutomerService in mkyong's example.
For example i have controller which calls CustomerService,
#RestController
#RequestMapping(value = "/customer")
public class CustomerController{
#Autowired CustomerService customerService;
#RequestMapping(value = "/getCustomer", method = RequestMethod.GET")
public ResponseEntity<CommonResponse> getService(){
customerService.printName();
}
}
It didn't worked.
i have tried this also:
#Autowired
private ProxyFactoryBean customerServiceProxy;
#RequestMapping(value = "/getCustomer", method = RequestMethod.GET")
public ResponseEntity<CommonResponse> getService(){
CustomerService customerService = (CustomerService) customerServiceProxy
.getTargetSource().getTarget();
customerService.printName();
}
}
this dosent work either.
Any Solution for this?
my bean-config.xml is same as mkyong's example.
It worked ! Just need to change proxy class from "org.springframework.aop.framework.ProxyFactoryBean" to
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
Auto proxy creator identifies beans to proxy via a list of names. So we don,t need to specify target bean instead list of beans can be specified and it will intercept automatically.
My config look as below:
<bean id="adviceAround" class="com.tdg.ess.semantic.event.log.AdviceAround" />
<!-- Event logging for Service -->
<bean id="testServicePointCut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedNames">
<list>
<value>process</value>
</list>
</property>
</bean>
<bean id="testServiceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="testServicePointCut" />
<property name="advice" ref="adviceAround" />
</bean>
<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<!-- Differnt beans which have certain service defined like CustomerService-->
<value>testService1</value>
<value>testService2</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>testServiceAdvisor</value>
</list>
</property>
</bean>
Thanks everyone for looking into.
I am using JMX in Spring application with XML configuration:
<bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=bean1" value-ref="bean1"/>
<entry key="bean:name=bean2" value-ref="bean2"/>
<entry key="bean:name=bean3" value-ref="bean3"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="*">
<bean class="com.test.listener"/>
</entry>
</map>
</property>
</bean>
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="1099" />
</bean>
<bean id="serverConnector"
class="org.springframework.jmx.support.ConnectorServerFactoryBean">
<property name="objectName" value="connector:name=rmi" />
<property name="serviceUrl"
value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxrmi" />
</bean>
I understand from various documents like instead of this XML configuration we could annotate it with #EnableMBeanExport and with #ManagedResource for the beans.
But i doubt how ConnectorServerFactoryBean gets configured with these annotations. Or is there any annotation available to configure RMI and connectorServerFactoryBean?
Also i need to know how to annotate, notificationListenerMappings configured?
P.S:
I have the code working for publisher and listener under XML configuration. I am planning to move it completely on annotation based as i do not want to disturb XML configuration already in PROD.
Edited
Found the following piece of code: planning to try it:
#Bean
public RmiRegistryFactoryBean registry() {
return new RmiRegistryFactoryBean();
}
#Bean
#DependsOn("registry")
public ConnectorServerFactoryBean connectorServer() throws MalformedObjectNameException {
ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setObjectName("connector:name=rmi");
connectorServerFactoryBean.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/connector");
return connectorServerFactoryBean;
}
Edit 2:
I am proceeding on above mentioned approach and I am able to configure MBeans and able to publish notifications. But unfortunately I am stuck up with configuring NotificationListener through Annotation.
I tried adding the following:
#Bean
#DependsOn("registry")
public ConnectorServerFactoryBean connectorServer() throws MalformedObjectNameException {
ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setObjectName("connector:name=rmi");
connectorServerFactoryBean.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/connector");
//TestListener is my NotificationListener class
ObjectName objectName = new ObjectName("bean:name=bean1");
connectorServerFactoryBean.getServer().addNotificationListener(objectName,
new TestListener(), null,null);
return connectorServerFactoryBean;
}
I am getting instanceNotFoundException stating bean:name=bean1 is not found. But I have configured like, #ManagedResource(objectName="bean:name=bean1") on my bean1.
Any help please on what i am missing?
#EnableMBeanExport has a server property, which reference the bean name of a server object.
see for example the test of this component, which use this server property : https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java
I am new to spring. Admins of my spring based web app want to configure settings from the web interface, so users can authenticate against LDAP server with their company username and password.
Change in LDAP settings should be possible without restarting the application. This might happen during a 'migration' or whatever reason. I have a couple beans, which need to be refreshed after the admin saves new settings for the LDAP server:
<bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg>
<list>
<value>${ldap.url1}</value>
...
</list>
</constructor-arg>
<constructor-arg value="${ldap.basedn}"</constructor-arg>
<property name="referral" value="${ldap.referral}" />
<property name="baseEnvironmentProperties">...</property>
<property name="userDn" value="${ldap.username}" />
<property name="password" value="${ldap.password}" />
</bean>
I am using Springframework 3.1.2. The problem is, there are constructor arguments, which I want to change and not affect other running jobs. I tried playing with Scoped proxy, but not to much success yet:
<bean id="ldapServer" scope="prototype" ...>
<aop:scoped-proxy/>
I was successful though to get ldapServer to reinstantiate, when using prototype scope by running this piece of code:
#Controller
public class LDAPSettingsController implements ApplicationContextAware {
public ModelAndView handleRequest(...) {
DefaultSpringSecurityContextSource ldap;
ldap = context.getParentBeanFactor().getBean("ldapServer");
System.out.println(ldap.hashCode());
return new ModelAndView(new RedirectView('login.jsp'));
}
...
}
Are scopes and proxies here the way to go, or is the another mechanism in Spring to reflect configuration changes into a running program instance?
UPDATE: Clear up the question.
UPDATE: The root problem with the AOP proxies was following root exception:
java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
What worked was adding proxy-target-class="false" attribute to the <aop:scoped-proxy/> tag. I created a new scope, which works better than prototype - It destroys beans on settings update. Now I have this in my beans.xml:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="ldap">
<ref bean="ldapScope" />
</entry>
</map>
</property>
</bean>
<bean id="ldapScope" class="com.myapp.SettingsScope" />
<bean id="ldapServer" scope="ldap" ...>
<aop:scoped-proxy proxy-target-class="false"/>
<constructor-args>
<list><value>${ldap.url1}</value> .. </list>
</constructor-args>
...
</bean>
I also have a controller for LDAP settings into which I inject ldapScope and I call a method which destroys current life-cycle objects and starts a new life-cycle every time, user presses the apply button.
PS: Not sure if I handle the life-cycle "re-start" in the right way - people my way to look for auto-start beans and start them after such event happens (i.e.: Setting -> Apply)
I'm trying to add a simple redirect into a web application built in Restlets, and it's proving non-trivial. The task is a simple one: I want to actually redirect all missing files from a web application to the same static file.
I'm using org.restlet.routing.Redirector with the following values (I'm using Spring injection):
<bean name="router" class="org.restlet.ext.spring.SpringRouter">
<constructor-arg ref="trackerComponentChildContext" />
<property name="attachments">
<map>
<entry key="/api" value-ref="apiRouter" />
<entry key="/statics" value-ref="staticsDirectory" />
<entry key="/" value-ref="staticsRedirector" />
</map>
</property>
</bean>
<bean id="staticsRedirector" class="ca.uhnresearch.pughlab.tracker.restlets.CustomRedirector">
<constructor-arg ref="trackerComponentChildContext" />
<constructor-arg value="{o}/statics/index.html" />
<constructor-arg value="7" />
</bean>
I can play with the file hierarchy relatively simply, but I just want to send anything that doesn't match either /api or /statics to /statics/index.html within the same application.
Restlet is almost getting it, and it does seem now to pick up the reference to the correct file, it just doesn't quite serve it.
I've put a working copy of the whole thing (including Thierry's suggestions below) at: https://github.com/morungos/restlet-spring-static-files. What I'd like to happen is something like the equivalent sequential attempts below:
curl http://localhost:8080/statics/**/* to hit the corresponding /statics/**/*
curl http://localhost:8080 to hit the main /statics/index.html
curl http://localhost:8080/**/* to hit the main /statics/index.html
I made some tests regarding your issue and I can't figure out how to have your message :-(. Perhaps it's because I haven't the whole code.
In fact, I saw a problem at the level of the SpringRouter itself. I would like to attach the redirector with an attachDefault and not an attach("/", ...) / attach("", ...). The method setDefaultAttachment actually does an attach("", ...).
So I made work something with the following updates:
Create a custom SpringRouter
public class CustomSpringRouter extends SpringRouter {
public void setDefaultAttachment(Object route) {
if (route instanceof Redirector) {
this.attachDefault((Restlet) route);
} else {
super.setDefaultAttachment(route);
}
}
}
Create a custom Redirector. I got the context from the component instead of a child context.
public class CustomRedirector extends Redirector {
public CustomRedirector(Component component, String targetPattern, int mode) {
super(component.getContext(), targetPattern, mode);
}
}
I then use the following Spring configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myComponent" class="org.restlet.ext.spring.SpringComponent">
<property name="defaultTarget" ref="router" />
</bean>
<bean name="router" class="test.CustomSpringRouter">
<property name="attachments">
<map>
<entry key="/api" value-ref="apiRouter" />
<entry key="/statics" value-ref="staticsDirectory" />
</map>
</property>
<property name="defaultAttachment" ref="staticsRedirector" />
</bean>
<bean id="staticsRedirector" class="test.CustomRedirector">
<constructor-arg ref="myComponent" />
<constructor-arg value="{o}/statics/index.html" />
<constructor-arg value="7" />
</bean>
<bean name="apiRouter" class="org.restlet.ext.spring.SpringRouter">
(...)
</bean>
(...)
</beans>
Hope it helps you,
Thierry
Probably missing something completely obvious here, but here goes. I'm starting out with Spring MVC. I have a form controller to process inbound requests to /share/edit.html. When I hit this url from my browser, I get the following error:
The requested resource (/inbox/share/share/edit) is not available.
Here is my applicationContext-mvc.xml:
<bean id="publicUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
<property name="mappings" >
<value>
/share/edit.html=shareFormController
/share/list.html=shareController
/share/view.html=shareController
/folders.json=foldersController
/studies.json=studiesController
</value>
</property>
</bean>
<bean id="internalPathMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver" />
<bean id="shareFormController" class="com.lifeimage.lila.controller.ShareFormController" />
<bean id="shareController" class="com.lifeimage.lila.controller.ShareController" >
<property name="methodNameResolver" ref="internalPathMethodNameResolver" />
</bean>
and my form Controller:
public class ShareFormController extends SimpleFormController {
public ShareFormController() {
setCommandClass( Share.class );
}
#Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
throws Exception {
//controller impl...
}
}
You should look at your view resolver. Make sure that it is resolving the logical name in your controller as you think it should. Looks like the name it is resolving it to does not exist currently
I think I've resolved this issue. There were two problems:
1) Implementations of SimpleFormController require a form and success view; which I had not configured here. As this is a server method for an AJAX client, I added a Spring-JSON view as follows:
<?xml version="1.0" encoding="UTF-8"?>
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
default-lazy-init="false" default-autowire="no"
default-dependency-check="none">
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="jsonErrors">
<list>
<ref bean="statusError" />
<ref bean="modelflagError" />
</list>
</property>
</bean>
<bean name="statusError"
class="org.springframework.web.servlet.view.json.error.HttpStatusError">
<property name="errorCode"><value>311</value></property>
</bean>
<bean name="modelflagError"
class="org.springframework.web.servlet.view.json.error.ModelFlagError">
<property name="name"><value>failure</value></property>
<property name="value"><value>true</value></property>
</bean>
which can be used for all controllers that return JSON.
2) I switched from a SimpleURLHandlerMapping to ControllerClassNameHandlerMapping and relied on Spring naming conventions ( controllerClassName/method.html ), which fixed the routing issue. Might not be a long term solution, but got me through the task.
Did you check your log output? Spring MVC is generally pretty verbose in what it outputs.
Also, the URL you've posted (/inbox/share/share/edit) does not seem to match what you are configuring (/share/edit.html).
#jordan002 when I see all the hoops you had to jump to accomplish your task, I feel obliged to share a very powerful Java MVC framework that requires much less configuration. The framework is called Induction, check out the article Induction vs. Spring MVC, http://www.inductionframework.org/induction-vs-spring-mvc.html