I'm trying to export some information with Spring JMX annotation driven (I have no xml :D). I have achieved to export Strings and Integer types but I haven't been able to export any object of a class I created.
This is my #Configuration class.
#Configuration
#EnableMBeanExport
#ComponentScan({"my.packages"})
public class AppManager {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppManager.class);
context.refresh();
try {
TimeUnit.MINUTES.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Bean(name = "jmxExporter")
public Exporter jmxExporter() {
return new Exporter();
}
}
This is some class I have with some attributes I want to get.
public class MyClass implements Serializable {
private int param1;
private int param2;
private int param3;
public MyClass() {
// calculate all params
}
public int getParam1() {
return this.param1;
}
public int getParam2() {
return this.param2;
}
public int getParam3() {
return this.param3;
}
}
This is the class that exports it's attributes.
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
#ManagedResource(objectName = "my.packages:type=JMX,name=Exporter")
public class Exporter {
#ManagedAttribute
public String getString() { //This works!
return "Test string";
}
#ManagedAttribute
public MyClass getMyClass() { //This does not work
return new MyClass();
}
}
I need to create MyClass object every time because it has some real-time information that I can't export separately.
In JConsole the value of attribute is "Unavailable".
I'm pretty new to JMX and obviously missing something.
Thank you for your help!
I resolved it by returning CompositeData.
#ManagedAttribute
public CompositeData getMyClass() {
return createCompositeDataForMyClass();
}
I built a CompositeDataSupport for that and it worked.
return new CompositeDataSupport(compositeType, itemNames, itemValues);
Where compositeType is a CompositeType, itemNames is a String[] and itemValues is an Object[].
The CompositeType can be built with something like this
new CompositeType(typeName, typeDescription, itemNames, itemDescriptions, itemTypes);
typeName, typeDescription are Strings. itemNames and itemDescriptions are String[]. itemTypes is an OpenType[]. SimpleType and CompositeType can be used to build OpenType.
All this objects must be imported with
import javax.management.openmbean.*;
Related
I am working within an environment that changes credentials every several minutes. In order for beans that implement clients who depend on these credentials to work, the beans need to be refreshed. I decided that a good approach for that would be implementing a custom scope for it.
After looking around a bit on the documentation I found that the main method for a scope to be implemented is the get method:
public class CyberArkScope implements Scope {
private Map<String, Pair<LocalDateTime, Object>> scopedObjects = new ConcurrentHashMap<>();
private Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>();
private Integer scopeRefresh;
public CyberArkScope(Integer scopeRefresh) {
this.scopeRefresh = scopeRefresh;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name) || scopedObjects.get(name).getKey()
.isBefore(LocalDateTime.now().minusMinutes(scopeRefresh))) {
scopedObjects.put(name, Pair.of(LocalDateTime.now(), objectFactory.getObject()));
}
return scopedObjects.get(name).getValue();
}
#Override
public Object remove(String name) {
destructionCallbacks.remove(name);
return scopedObjects.remove(name);
}
#Override
public void registerDestructionCallback(String name, Runnable runnable) {
destructionCallbacks.put(name, runnable);
}
#Override
public Object resolveContextualObject(String name) {
return null;
}
#Override
public String getConversationId() {
return "CyberArk";
}
}
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk")
public String dateString(){
return LocalDateTime.now().toString();
}
}
#RestController
public class HelloWorld {
#Autowired
private String dateString;
#RequestMapping("/")
public String index() {
return dateString;
}
}
When I debug this implemetation with a simple String scope autowired in a controller I see that the get method is only called once in the startup and never again. So this means that the bean is never again refreshed. Is there something wrong in this behaviour or is that how the get method is supposed to work?
It seems you need to also define the proxyMode which injects an AOP proxy instead of a static reference to a string. Note that the bean class cant be final. This solved it:
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk", proxyMode=ScopedProxyMode.TARGET_CLASS)
public NonFinalString dateString(){
return new NonFinalString(LocalDateTime.now());
}
}
I have instantiated a parametrized constructor here called request operation with dynamic values. how to #Autowire this to Requestclass? subsequently, in Request class, I have created a new RatingResponse how to #Autowire this as well?
class Initializer
public class Intializer
{
NewClass newclass = new NewClass();
String testName = Number + "_" + "Test"; -->getting the String number dynamically
Test test = new Test(testName); -> this is a different class
Operation operation = new RequestOperation(test, newclass ,
sxxx, yyy, zzz); - argumented constructor
opertaion.perform();
}
RequestClass
public class RequestOperation implements Operation {
// the constructor
public RequestOperation(Test test, Sheet reportSheet, XElement element, TestDataManager testDataManager, Report report)
{
this.test = test;
this.newclass = newclass ;
this.sxxx= sxxx;
this.yyy= yyy;
this.zzz= zzz;
}
#Override
public boolean perform(String CompanyName, String Province) {
Response response = new RatingResponse(this.test, this.reportSheet,
callService(this.buildRequest(CompanyName, Province)), this, this.report);-> create a new paramterizedconstructor
}
private String buildRequest(String CompanyName, String Province) {
return pm.getAppProperties().getProperty(constructedValue); }
}
**Response class **
public class RatingResponse implements Response {
public RatingResponse(Test test, Sheet reportSheet, Object obj, RequestOperation requestOperation, Report report) {
this.test = test;
if (obj instanceof Document) {
this.document = (Document) obj;
}
this.operation = requestOperation;
this.reportSheet = reportSheet;
this.report = report;
}
** interface **
#Component
public interface Operation {
public boolean perform(String Name, String Province);
}
#Component
public interface Response {
void construct();
}
In spring boot, you can autowire only types marked with #Bean or classes marked with #Component or its derivitives like #Service, #Controller
The speciality of these annotations is that only a single instance of the class is kept in memory.
So if your requirement needs you to create new classes for each set of new dynamic values, then autowiring them is not the right way to go.
However if you have limited number of possible dynamic values that your class can have, you can create beans for each of them like this
#Configuration
class MyBeans{
#Bean
public RatingResponse ratingResponse(){
Response response = new RatingResponse(this.test, this.reportSheet,
callService(this.buildRequest(CompanyName, Province)), this, this.report);
return response
}
}
Then in the class you need to use it, you can do
#Autowired
RatingResponse ratingResponse
First I'm not sure if it's a good idea to do all this.
Goal is to create some interfaces with annotations to hide legacy position based string access out of a configuration database, without implementing each interface.
Declarative configured Interface:
public interface LegacyConfigItem extends ConfigDbAccess{
#Subfield(length=3)
String BWHG();
#Subfield(start = 3, length=1)
int BNKST();
#Subfield(start = 4, length=1)
int BEINH();
:
}
Base interface for runtime identification
public interface ConfigDbAccess{
}
Dummy implementation without functionality, may change.
public class EmptyImpl {
}
Beanfactory and MethodInvocation interceptor, to handle the unimplemented methods.
#Component
public class InterfaceBeanFactory extends DefaultListableBeanFactory {
protected static final int TEXT_MAX = 400;
#Autowired
private EntityRepo entityRepo;
public <T> T getInstance(Class<T> legacyInterface, String key) {
ProxyFactory factory = new ProxyFactory(new EmptyImpl());
factory.setInterfaces(legacyInterface);
factory.setExposeProxy(true);
factory.addAdvice(new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
KEY keyAnnotation = invocation.getThis().getClass().getAnnotation(Key.class);
String key= keyAnnotation.key().toUpperCase();
String ptart = invocation.getMethod().getDeclaringClass().getSimpleName();
Vpt result = entityRepo.getOne(new EntityId(ptart.toUpperCase(), schl.toUpperCase()));
Subfield sub = invocation.getMethod().getAnnotation(Subfield.class);
//TODO: Raise missing Subfield annotation
int start = sub.start();
int length = sub.length();
if (start + length > TEXT_MAX) {
//TODO: Raise invalid Subfield config
}
String value = result.getTextField().substring(start,start+length);
return value;
}
});
return (T) factory.getProxy();
}
#Override
protected Map<String, Object> findAutowireCandidates(String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
Map<String, Object> map = super.findAutowireCandidates(beanName, requiredType, descriptor);
if (ConfigDbAccess.class.isAssignableFrom(requiredType )) {
:
#SpringBootApplication
public class JpaDemoApplication {
#Autowired
private ApplicationContext context;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(JpaDemoApplication.class);
// app.setApplicationContextClass(InterfaceInjectionContext .class);
app.run(args);
}
public class InterfaceInjectionContext extends AnnotationConfigApplicationContext {
public VptInjectionContext () {
super (new InterfaceBeanFactory ());
}
}
So far I got all this stuff working, except when I try to set the applications Context class to my DefaultListableBeanFactory, I'm killing the Spring boot starter web. The application starts, injects the the Autowired fields with my intercepted pseudo implementaition --- and ends.
I think I'm doing something wrong with registering the DefaultListableBeanFactory, but I've no idea how to do it right.
To get this answered:
M. Deinum pointed me to a much simpler solution:
Instead of creating a BeanFactory I installed a BeanPostProcessor with this functioniality.
#RestController
public class DemoRestController {
#Autowired
VptService vptService;
#ConfigItem(key="KS001")
private PrgmParm prgmKs001;
#ConfigItem(key="KS002")
private PrgmParm prgmKs002;
public DemoRestController() {
super();
}
Where the ConfigItem annotation defines the injection point.
Next I created a CustomBeanPostProcessor which scans all incoming beans for
fields having a ConfigItem annotation
#Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
for (Field field : bean.getClass().getDeclaredFields()) {
SHL cfgDef = field.getAnnotation(ConfigItem.class);
if (cfgDef != null) {
Object instance = getlInstance(field.getType(), cfgDef.key());
boolean accessible = field.isAccessible();
field.setAccessible(true);
try {
field.set(bean, instance);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
field.setAccessible(accessible);
}
}
return bean;
}
The getInstnce(field.getType(),cfgDef.key()) creates a proxy with the MethodInterceptor, which does the work.
There are a lot of things to finalize, but all in all it looks good to me.
My overall goal is to load properties from a properties file and then inject those properties into my objects. I would also like to use those properties to instantiate certain singleton classes using Guice. My singleton class looks like this:
public class MainStore(){
private String hostname;
#Inject
public void setHostname(#Named("hostname") String hostname){
this.hostname = hostname;
}
public MainStore(){
System.out.println(hostname);
}
}
I'm trying to instantiate a singleton using this provider:
public class MainStoreProvider implements Provider<MainStore> {
#Override
public MainStore get(){
MainStore mainStore = new MainStore();
return mainStore;
}
}
My configurationModule is a module that loads a configuration from a property file specified at runtime:
public class ConfigurationModule extends AbstractModule {
#Override
protected void configure(){
Properties properties = loadProperties();
Names.bindProperties(binder(), properties);
}
private static Properties loadProperties() {
String resourceFileName = "example.properties";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(resourceFileName);
Properties properties = new Properties();
properties.load(inputStream);
return properties;
}
}
And my example.properties files contains:
hostname = testHostName
Then when I need the MainStore singleton I'm using:
Injector injector = Guice.createInjector(new ConfigurationModule());
MainStoreProvider mainStoreProvider = injector.getInstance(MainStoreProvider.class);
MainStore mainStore = mainStoreProvider.get(); //MainClass singleton
Is this the right path to go down? Should I be doing this a completely different way? Why does my MainStore not print out the correct hostname?
I have written up a small example that demonstrates how to bind a Singleton, how to inject a property and so on.
public class TestModule extends AbstractModule {
#Override
protected void configure() {
Properties p = new Properties();
p.setProperty("my.test.string", "Some String"); // works with boolean, int, double ....
Names.bindProperties(binder(),p);
bind(X.class).to(Test.class).in(Singleton.class); // This is now a guice managed singleton
}
public interface X {
}
public static class Test implements X {
private String test;
#Inject
public Test(#Named("my.test.string") String test) {
this.test = test;
System.out.println(this.test);
}
public String getTest() {
return test;
}
}
public static void main(String[] args) {
Injector createInjector = Guice.createInjector(new TestModule());
Test instance = createInjector.getInstance(Test.class);
}
}
The configure method is now responsible to tell guice that my Test class is a singleton.
It prints the correct hostname (property test) because I inject the constructor and set the property.
You can do this with a provider as well, however you will then have to create your objects manually. In my case, this would look like this:
public static class TestProvider implements Provider<X> {
private String test;
private X instance;
public TestProvider(#Named("my.test.string") String test) {
this.test = test;
}
#Override
public X get() {
if(instance == null) {
instance = new Test(test);
}
return instance;
}
}
Binding will then look like this:
bind(X.class).toProvider(TestProvider.class);
Is this what you wanted?
Cheers,
Artur
Edit:
I did some test and found this to note:
You can bind a provider as a singleton:
bind(X.class).toProvider(TestProvider.class).in(Singleton.class);
That way you do not need to handle singleton creation yourself:
public static class TestProvider implements Provider<X> {
private String test;
private X instance;
#Inject
public TestProvider(#Named("my.test.string") String test) {
this.test = test;
}
#Override
public X get() {
return instance;
}
}
The above code will create singletons of the object X.
I have a android application, but it is not relevant.
I have a class called "Front controller" which will receive some message
through it's constructor. The message, for brievity, could be an integer.
I want somewhere else to create a new controller which will execute
a method based on the integer defined above
public class OtherController {
#MessageId("100")
public void doSomething(){
//execute this code
}
#MessageId("101")
public void doSomethingElse(){
//code
}
}
The front controller could be something like this:
public class FrontController {
private int id;
public FrontController(int id){
this.id=id;
executeProperControllerMethodBasedOnId();
}
public void executeProperControllerMethodBasedOnId(){
//code here
}
public int getId(){
return id;
}
}
So, if the Front Controller will receive the integer 100, it
will execute the method annotated with #MessageId(100). The
front controller don't know exactly the class where this method
is.
The problem which I found is that I need to register somehow
each controller class. I Spring I had #Component or #Controller
for autoloading. After each controllers are register, I need to
call the properly annotated method.
How to achieve this task? In Spring MVC, I had this system
implemented, used to match the HTTP routes. How could I implement
this in a plain java project?
Any suggestions?
Thanks to Google Reflections (hope you can integrate this in your android project.)
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections-maven</artifactId>
<version>0.9.8</version>
</dependency>
For optimisation I've added the requirement to also annotate the class with MessageType annotation and the classes should be in the same package (org.conffusion in my example):
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MessageType {
}
The OtherController looks like:
#MessageType
public class OtherController {
#MessageId(id=101)
public void method1()
{
System.out.println("executing method1");
}
#MessageId(id=102)
public void method2()
{
System.out.println("executing method2");
}
}
The implementation will look like:
public void executeProperControllerMethodBasedOnId() {
Set<Class<?>> classes = new org.reflections.Reflections("org.conffusion")
.getTypesAnnotatedWith(MessageType.class);
System.out.println("found classes " + classes.size());
for (Class<?> c : classes) {
for (Method m : c.getMethods()) {
try {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object o = c.newInstance();
if (mid.id() == id)
m.invoke(o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Maybe you can optimise and build a static hashmap containing already scanned message ids.
You need to implement some of the work by yourself using reflection, I would recommend to prepare message handlers on initial phase in regards to performance. Also you possibly want to think about Singleton/Per Request controllers. Some of the ways to implement the solution:
interface MessageProcessor {
void execute() throws Exception;
}
/* Holds single instance and method to invoke */
class SingletonProcessor implements MessageProcessor {
private final Object instance;
private final Method method;
SingletonProcessor(Object instance, Method method) {
this.instance = instance;
this.method = method;
}
public void execute() throws Exception {
method.invoke(instance);
}
}
/* Create instance and invoke the method on execute */
class PerRequestProcessor implements MessageProcessor {
private final Class clazz;
private final Method method;
PerRequestProcessor(Class clazz, Method method) {
this.clazz = clazz;
this.method = method;
}
public void execute() throws Exception {
Object instance = clazz.newInstance();
method.invoke(instance);
}
}
/* Dummy controllers */
class PerRequestController {
#MessageId(1)
public void handleMessage1(){System.out.println(this + " - Message1");}
}
class SingletonController {
#MessageId(2)
public void handleMessage2(){System.out.println(this + " - Message2");}
}
class FrontController {
private static final Map<Integer, MessageProcessor> processors = new HashMap<Integer, MessageProcessor>();
static {
try {
// register your controllers
// also you can scan for annotated controllers as suggested by Conffusion
registerPerRequestController(PerRequestController.class);
registerSingletonController(SingletonController.class);
} catch (Exception e) {
throw new ExceptionInInitializerError();
}
}
private static void registerPerRequestController(Class aClass) {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
processors.put(mid.value(), new PerRequestProcessor(aClass, m));
}
}
}
private static void registerSingletonController(Class aClass) throws Exception {
for (Method m : aClass.getMethods()) {
if (m.isAnnotationPresent(MessageId.class)) {
MessageId mid = m.getAnnotation(MessageId.class);
Object instance = aClass.newInstance();
processors.put(mid.value(), new SingletonProcessor(instance, m));
}
}
}
/* To process the message you just need to look up processor and execute */
public void processMessage(int id) throws Exception {
if (processors.containsKey(id)) {
processors.get(id).execute();
} else {
System.err.print("Processor not found for message " + id);
}
}
}