IMEI I am new to MXbeans. I want to understand when is the MXBean actually initialized, in the application which I am supporting we have a notification system and I can not see my MXBean in JConsole until there is some notification arriving. Here is a code of my MXBean.
package mecomaany.instrumentation;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import BulkCMIRP_MxBean;
import SoapIRPLogger;
/**
* This dynamic MBean exposes a method to return the 10 latest Basic CM
* operations.
*
* #author eshtrom
*
*/
public class BasicCMIRP_MxBean implements DynamicMBean{
private static final String CLASS_NAME = BasicCMIRP_MxBean.class.getCanonicalName();
private static final String MX_BEAN_NAME = BasicCMIRP_MxBean.class.getCanonicalName() + ":Type=BasicCMIRP_MxBean";
private static final String BEAN_DESCRIPTION = "Instrumentation bean for SOAP Basic CM IRP.";
private static final int NUM_OPERATIONS_TO_RECORD = 10;
private final ArrayList<String> basicCMOperations = new ArrayList<String>();
/**
* Register the bean. This is a best effort attempt. If registration fails
* we'll report it but nothing more.
*/
public BasicCMIRP_MxBean() {
registerMxBean();
}
/**
* Attempt to unregister and clean up the MX beans.
*/
public void destroy() {
basicCMOperations.clear();
unregisterMxBean();
}
/**
* This method returns a description of this bean to the JMX interface. The
* description is just a list of names of the currently stored attributes.
*/
public synchronized MBeanInfo getMBeanInfo() {
final MBeanAttributeInfo[] attributes = new MBeanAttributeInfo[0];
final MBeanOperationInfo[] operations = { new MBeanOperationInfo("getBasicCMInstrumentation", "Get instrumentation Basic CM IRP bean.", null, "String[]",
MBeanOperationInfo.INFO) };
return new MBeanInfo(this.getClass().getName(), BEAN_DESCRIPTION, attributes, null, operations, null);
}
/**
* Callback to execute methods exposed by this dynamic MBean.
*/
public Object invoke(final String actionName, final Object[] params, final String[] signature) throws MBeanException, ReflectionException {
SoapIRPLogger.enter(CLASS_NAME, "invoke");
if (actionName != null) {
if (actionName.equals("getBulkCMInstrumentation")) {
return getBasicCMInstrumentation();
}
}
SoapIRPLogger.exit(CLASS_NAME, "invoke");
throw new ReflectionException(new NoSuchMethodException(actionName));
}
/**
* Construct a human readable very of the last 10 operations and return it.
*
* #return string array as an object.
*/
private Object getBasicCMInstrumentation() {
SoapIRPLogger.enter(CLASS_NAME, "getBasicCMInstrumentation");
String[] result = new String[basicCMOperations.size()];
int index = 0;
for (String operation : basicCMOperations) {
result[index] = operation;
index++;
}
SoapIRPLogger.exit(CLASS_NAME, "getBasicCMInstrumentation");
return result;
}
/**
* No attributes are writable so this method will throw an exception.
*/
public void setAttribute(final Attribute arg0) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
throw new AttributeNotFoundException("All attributes on this bean are read only.");
}
/**
* No attributes are writable so this method will return an empty list.
*/
public AttributeList setAttributes(final AttributeList arg0) {
return new AttributeList();
}
public Object getAttribute(final String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
throw new AttributeNotFoundException("No attributes are defined on this MX bean.");
}
/**
* No attributes are readable so this method will return an empty list.
*/
public AttributeList getAttributes(final String[] attributes) {
return new AttributeList();
}
/**
* Add or update and instrumentation attribute. A null attribute name will
* be ignored.
*
* #param name
* #param value
*/
public void updateInstrumentationAttibute(final String name, final String value) {
// The only attribute that this bean supports is Bulk CM operations.
if (name.compareTo("BasicCM_Operations") == 0) {
basicCMOperations.add(value);
// We'll only record a maximum of 10 operations. If we exceed the
// max, remove the oldest.
if (basicCMOperations.size() > NUM_OPERATIONS_TO_RECORD) {
basicCMOperations.remove(0);
}
}
}
public ObjectName getBeanName() throws MalformedObjectNameException, NullPointerException {
// Construct the ObjectName for the MBean we will register
return new ObjectName(MX_BEAN_NAME);
}
/**
* Register the bean.
*/
protected void registerMxBean() {
try {
ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.getBeanName());
} catch (Exception e) {
SoapIRPLogger.exception(CLASS_NAME, "Constructor", "Failed to register BulkCMIRP_MxBean management beans.", e);
}
}
protected void unregisterMxBean() {
try {
ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.getBeanName());
} catch (Exception e) {
// Suppress exceptions, we're closing down anyway.
}
}
}
Loner;
Your MXBean should be visible in JConsole as soon as you construct it, since the constructor calls registerMxBean() which registers the MBean with the platform MBeanServer.
Assuming your JConsole is already running when the MBean is registered, JConsole's view of the MBean will be dictated by the first instance of the MBeanInfo that is generated on registration. Since you coded this as a DynamicMBean, I wonder if your intent was to periodically modify the MBeanInfo, but be aware that once a JConsole connection has retrieved the MBeanInfo for a registered bean, it will not refresh it. If the MBeanInfo changes, you must closed the connection in JConsole and open it again.
Consequently, your issue may be outside the code you have supplied, or more simply put, when is the instance of BasicCMIRP_MxBean created ?
Your comment about not seeing the bean until notifications start arriving makes me wonder if you mean that:
A. You cannot see the MBean until notifications start arriving, in which case I would assume that there is some activation code that creates the instance when a [the first ?] notification arrives, or
B. What you mean is that you cannot see specific properties of the MBean until notifications start arriving.
Perhaps you could clarify the larger picture here.
Some additional observations that may be unrelated:
The MBeanInfo you are generating specifies that the one and only operation is called getBasicCMInstrumentation (basic), but your invoke handler only attempts to decode an operation called getBulkCMInstrumentation (bulk). JConsole is supplied the MBeanInfo in order to render the operations so the console believes that the operation is called basic but the MBean will only respond to a request called bulk.
The signature for method getBasicCMInstrumentation returns an Object but what the code really returns is a String[]. This may work because your MBeanInfo specifies that a String[] is returned, but for consistency and clarity I would change the method signature.
//Nicholas
Related
I am using CompositeFileListFilter to add two filters. Firstly, I want to execute AbstractPersistentFileListFilter with the default implementation, thereby protecting it from duplication.
Second, I use my own implementation, which checks the database for the existence of a file, protecting me from duplicates in the event of a system restart
How can this approach be released? So that the default implementation of AbstractPersistentFileListFilter with the internal memory of the MetadataStore is executed first
The goal is to reduce database calls to check for the existence of a file. Perhaps there is a better approach to the solution. Thanks for any help!
FtpConfiguration.java
#Bean
CompositeFileListFilter<FTPFile> getCompositeFileListFilter() {
CompositeFileListFilter<FTPFile> compositeFileListFilter = new CompositeFileListFilter<>();
compositeFileListFilter.addFilters(new CustomFileFilter(messageRepo));
return compositeFileListFilter;
}
#Bean
public IntegrationFlow ftpIntegrationFlow() {
return IntegrationFlows.from(
Ftp.inboundStreamingAdapter(template())
.filter(getCompositeFileListFilter())
.remoteDirectory("."),
e -> e.poller(Pollers.fixedDelay(500).advice(advice())))
.transform(new StreamTransformer("UTF-8"))
.handle(messageService::unmarshall)
.get();
}
CustomFileFilter.java
#Component
#Log4j2
public class CustomFileFilter implements FileListFilter<FTPFile> {
private final MessageRepo messageRepo;
public CustomFileFilter(MessageRepo messageRepo) {
this.messageRepo = messageRepo;
}
#Override
public List<FTPFile> filterFiles(FTPFile[] files) {
return null;
}
#Override
public boolean accept(FTPFile file) {
String fileName = file.getName();
log.info("file filter get name: {}", fileName);
Integer fileCheck = messageRepo.checkExistsMessage(fileName);
log.info("fileCheck: {}", fileCheck);
return fileCheck != 1;
}
#Override
public boolean supportsSingleFileFiltering() {
return true;
}
}
Use the ChainFileListFilter instead:
/**
* The {#link CompositeFileListFilter} extension which chains the result
* of the previous filter to the next one. If a filter in the chain returns
* an empty list, the remaining filters are not invoked.
*
* #param <F> The type that will be filtered.
*
* #author Artem Bilan
* #author Gary Russell
* #author Cengis Kocaurlu
*
* #since 4.3.7
*
*/
public class ChainFileListFilter<F> extends CompositeFileListFilter<F> {
https://docs.spring.io/spring-integration/docs/current/reference/html/file.html#file-reading
Starting with version 4.3.7, a ChainFileListFilter (an extension of CompositeFileListFilter) has been introduced to allow scenarios when subsequent filters should only see the result of the previous filter. (With the CompositeFileListFilter, all filters see all the files, but it passes only files that have passed all filters). ...
I am trying to implement a queue for a class that fetches OpenGraph data for a url. The idea is that the OpenGraphIO service only allows for one request at a time if the request requires their "proxy" service. To eliminate the "simultaneous proxy request" errors from the service, I would like to implement a request queue inside a service class called OpenGraphFetcherImpl. However, I can't figure out how to implement the actual queue itself inside the fetch() method. Obviously the fetch() method can be called in a multi-threaded environment.
My class shell is below:
public class OpenGraphFetcherImpl implements OpenGraphFetcher {
private static final String[] domainsThatRequireProxy = {"instagram.com","facebook.com"};
private static final LinkedList<URL> proxyQueue = new LinkedList<>();
private final String api_key;
public OpenGraphFetcherImpl(String api_key) {
this.api_key = api_key;
}
/**
* Fetch OpenGraph information for a url. If the url is invalid or no data is returned, the OpenGraph
* object will be "empty" (non-null)
*
* Only one "proxy" request can be made at a time. Should a proxy be needed, the request will be queued
* and returned once previous requests have been completed.
*
* #param url end point to fetch OpenGraph data
* #return OpenGraph object
*/
#Override
#Nonnull
public OpenGraph fetch(URL url) {
if (useProxy(url)) {
// Clearly this code doesn't work, but logic should be to add the request to the queue and then make requests in FIFO order
proxyQueue.add(url);
return OpenGraphIO.fetchOpenGraphInfo(api_key, proxyQueue.poll(), true);
} else {
return OpenGraphIO.fetchOpenGraphInfo(api_key, url, false);
}
}
/**
* #param url url to test
* #return true if the host of the url matches any domains that require use of a proxy
*/
private boolean useProxy(URL url) {
return Arrays.stream(domainsThatRequireProxy).parallel().anyMatch(url.getHost()::contains);
}
}
Based on your description, you'd want to limit synchronous calls to fetch() when useProxy is true. Then, you can use an object to synchronize that case only:
public class OpenGraphFetcherImpl implements OpenGraphFetcher {
private static final Object fetchLock=new Object();
public OpenGraph fetch(URL url) {
if (useProxy(url)) {
synchronized(fetchLock) {
return OpenGraphIO.fetchOpenGraphInfo(api_key, url, true);
}
} else {
return OpenGraphIO.fetchOpenGraphInfo(api_key, url, false);
}
}
...
The code examples are in PHP but the question is language agnostic.
Situation
I'm trying to figure out the best way to separate a service layer into multiple well defined layers.
In the example below I'm uploading a base64 encoded user avatar and showing how it would go through the layers. I'm using the decorator pattern to simulate the layers.
Important:
The data passed into each layer is usually changed in some way before it is passed into the next layer which is exactly what I'm looking for. The one thing I don't like about this is that in order to update an avatar you must first talk to the ValidatedProfile object instead of say a Profile object. Something about it seems weird but I could always have a Profile object which delegates calls to the ValidatedProfile.
The Layers
Validation:
This is where you validate the data. As in the example below it is where you check the format of the $avatar string and ensure it is a valid image resource. During the validation process entity objects and resources are often created which are then passed to the next layer.
Verification:
Perform checks such as verifying if a supplied ID is real. As in the example below this is where I check if the supplied user ID is actually the real ID of a user.
Commander:
Where the action to be performed happens. By the time this layer is reached the data is thought to be fully validated and verified and no further checks need to be done on it. The commander delegates the action to other services(usually entity services) and can also call other services do more actions.
Entity:
This layer works with actions to be performed on an entity and/or its relations.
ValidatedProfile
class ValidatedProfile
{
private $verifiedProfile;
/**
* #param string $avatar Example: data:image/png;base64,AAAFBfj42Pj4
*/
public function updateAvatar($userId, $avatar)
{
$pattern = '/^data:image\/(png|jpeg|gif);base64,([a-zA-Z0-9=\+\/]+)$/';
if (!preg_match($pattern, $avatar, $matches)) {
// error
}
$type = $matches[1]; // Type of image
$data = $matches[2]; // Base64 encoded image data
$image = imagecreatefromstring(base64_decode($data));
// Check if the image is valid etc...
// Everything went okay
$this->verifiedProfile->updateAvatar($userId, $image);
}
}
VerifiedProfile
class VerifiedProfile
{
private $profileCommander;
public function updateAvatar($userId, $image)
{
$user = // get user from persistence
if ($user === null) {
// error
}
// User does exist
$this->profileCommander->updateAvatar($user, $image);
}
}
ProfileCommander
class ProfileCommander
{
private $userService;
public function updateAvatar($user, $image)
{
$this->userService->updateAvatar($user, $image);
// If any processes need to be run after an avatar is updated
// you can invoke them here.
}
UserService
class UserService
{
private $persistence;
public function updateAvatar($user, $image)
{
$fileName = // generate file name
// Save the image to disk.
$user->setAvatar($fileName);
$this->persistence->persist($user);
$this->persistence->flush($user);
}
}
You could then have a Profile class like the following:
class Profile
{
private $validatedProfile;
public function updateAvatar($userId, $avatar)
{
return $this->validatedProfile->updateAvatar($userId, $avatar);
}
}
That way you just talk to an instance of Profile rather than ValidatedProfile which makes more sense I think.
Are there better and more widely accepted ways to achieve what I'm trying to do here?
I think you have too many layers. Two major objects should be enough for an operation like this. You need to validate the avatar input and persist it somehow.
Since you need to validate the user id and it is tied to persistence somehow, you can delegate that to the UserService object.
interface UserService {
/**
* #param string $userId
* #param resource $imageResource
*/
public function updateAvatar($userId, $imageResource);
/**
* #param string $userId
* #return bool
*/
public function isValidId($userId);
}
This checking for a valid user id should be a part of request validation. I would not make it a separate step like verification. So UserAvatarInput can handle that (validation implementation is just an example), and a little wrapper method to persist it all.
class UserAvatarInput {
/**
* #var UserService
*/
private $userService;
/**
* #var string
*/
private $userId;
/**
* #var resource
*/
private $imageResource;
public function __construct(array $data, UserService $service) {
$this->userService = $service; //we need it for save method
$errorMessages = [];
if (!array_key_exists('image', $data)) {
$errorMessages['image'] = 'Mandatory field.';
} else {
//validate and create image and set error if not good
$this->imageResource = imagecreatefromstring($base64);
}
if (!array_key_exists('userId', $data)) {
$errorMessages['userId'] = 'Mandatory field.';
} else {
if ($this->userService->isValidId($data['userId'])) {
$this->userId = $data['userId'];
} else {
$errorMessages['userId'] = 'Invalid user id.';
}
}
if (!empty($errorMessages)) {
throw new InputException('Input Error', 0, null, $errorMessages);
}
}
public function save() {
$this->userService->updateAvatar($this->userId, $this->imageResource);
}
}
I used an exception object to pass validation messages around.
class InputException extends Exception {
private $inputErrors;
public function __construct($message, $code, $previous, $inputErrors) {
parent::__construct($message, $code, $previous);
$this->inputErrors = $inputErrors;
}
public function getErrors() {
return $this->inputErrors;
}
}
This is how a client would use it, for example:
class UserCtrl {
public function postAvatar() {
try {
$input = new AvatarInput($this->requestData(), new DbUserService());
$input->save();
} catch (InputException $exc) {
return new JsonResponse($exc->getErrors(), 403);
}
}
}
I have a service interface that reads thus
package services;
import domain.Items;
public interface IItemsService extends IService {
public final String NAME = "IItemsService";
/** Places items into the database */
public void storeItem(Items items);
/** Retrieves items from the database
*
* #param category
* #param amount
* #param color
* #param type
* #return
* #throws ClassNotFoundException
*/
public Items getItems (String category, float amount, String color, String type) throws ItemNotFoundException, ClassNotFoundException;
}
And a factory that looks like this...
package services;
public class Factory {
public Factory(){}
#SuppressWarnings("unchecked")
public IService getService(String name) throws ServiceLoadException {
try {
Class c = Class.forName(getImplName(serviceName));
return (IService)c.newInstance();
} catch (Exception e) {
throw new ServiceLoadException(serviceName + "not loaded");
}
}
private String getImplName (String name) throws Exception {
java.util.Properties props = new java.util.Properties();
java.io.FileInputStream fis = new java.io.FileInputStream("properties.txt");
props.load(fis);
fis.close();
return props.getProperty(serviceName);
}
}
This should be really simple - but I keep getting two errors - IService cannot be resolved to a type (on both the factory and the service) and also an serviceName cannot be resolved into a variable error in the factory. I know I am missing something simple...
Regarding the type error: if IService is not in the package services, then IItemService will not have access to it and you will need to import some.package.name.IService.
The second answer is simple: in the getService and getImplName methods, the parameter is named name. In the method bodies, you're referring to it as serviceName. You should probably change name to serviceName in each of them.
If, on the other hand, you're trying to access an instance variable, note that in Java you have to declare all instance variables before you can access (read from/write to) them. You would need to modify the class as such:
public class Factory {
private String serviceName;
public Factory () {}
// other code
}
Well the second error is simple: there isn't a variable called serviceName. If you think there is, point to its declaration. I suspect you meant to use the parameter - in which case just change the parameter name to match the name you're trying to use:
public IService getService(String serviceName) throws ServiceLoadException
...
private String getImplName (String serviceName) throws Exception
This was a pretty simple error - you should think about what bit of your diagnosis let you down in working it out for yourself. (You should also indent your code more sensibly, btw.)
As for IService being missing - we have no idea where IService is meant to be declared, which makes it very hard to help you on this front...
Need help is deciding what approach needs to be taken to test below piece of code
I have one method called
private messageDAOInf messageDAO;
public Response verifyUser(Request request) {
Response response = null;
if (someCondition) {
/* -----------Some processing here---------- */
} else {
response = constructResponse(errorCode, errorDesc);
}
// Do more processing with messages from response
response = messageDAOInf
.convertMessagesAsAppropriate(response);
return response;
}
My EasyMock code is here
/** The message dao inf. */
private MessageDAOInf messageDAOInf;
private VerifyUserService verifyUserServiceI;
#Before
public void setUp() throws Exception {
messageDAOInf = EasyMock.createMock(MessageDAOInf.class);
verifyUserService = new VerifyUserService();
verifyUserService.setMessageDAOInf(messageDAOInf);
}
#Test
public void testErrorResponse() {
Request request = loadRequest();
Response response = constructErrorResponse();
EasyMock.expect(messageDAOInf.convertMessagesAsAppropriate(
response)).andReturn(response);
EasyMock.replay(messageDAOInf);
Response response2 = verifyUserService.verifyUser(request);
assertFailedResponse(response2);
}
The issue is from line
response = constructResponse(errorCode, errorDesc);
it constructs error response in verifyUser method and passes it to
messageDAOInf.convertMessagesAsAppropriate()
But with easy mock it passes some other instance (mocked one) and hence failes with error
java.lang.AssertionError:
Unexpected method call convertMessagesAsAppropriate(***Response#1bb35b***):
convertMessagesAsAppropriate(***Response#1b5d2b2***): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:56)
Let me know what approach I should take.
Thank you.
Your initial code expects that convertMessagesAsAppropriate will be called with the exact instance of Response that you created in the test: obviously it will not do that.
The correction you've made is essentially the same as using the built-in EasyMock.anyObject() method which will allow any Response instance. If that's all you want to check in your unit test, that's fine. Alternatively you can add extra logic into your ArgumentMatcher to prove that the Response that is passed as an argument really is an ErrorResponse, or Capture the response and examine it in your test. This all depends on your level of testing :-)
I have found out way of doing it.
You need to implement interface org.easymock.IArgumentMatcher
public class ObjectEquals implements IArgumentMatcher {
/** The expected. */
private Object expected;
/**
* Instantiates a new criterion equals.
*
* #param expected
* the expected
*/
public ObjectEquals(final Object expected) {
this.expected = expected;
}
/* (non-Javadoc)
* #see org.easymock.IArgumentMatcher#matches(java.lang.Object)
*/
public boolean matches(final Object actual) {
return expected.getClass().equals(actual.getClass());
}
/* (non-Javadoc)
* #see org.easymock.IArgumentMatcher#appendTo(java.lang.StringBuffer)
*/
public void appendTo(final StringBuffer buffer) {
buffer.append("buffer(");
}
}
and in your test class add method
/*
* Eq criterion.
*
* #param criterion the criterion
*
* #return the criterion
*/
public static <T> T eqCriterion(final Class<T> className, Object object) {
EasyMock.reportMatcher(new ObjectEquals(object));
return null;
}
Now while passing to easymock use method eqCriterion at line
EasyMock.expect(messageDAOInf.convertMessagesAsAppropriate(
response)).andReturn(response);
In short replace above line with
EasyMock.expect(messageDAOInf.convertMessagesAsAppropriate(
eqCriterion(Response.class, response))).andReturn(response);
This way it will use this mocked response instance instead of one generated by actual code.