How to create JMX client which can interect with multiple jmx server using different serviceUrl - spring

I am using Spring jmx to create jmx client which can interact with Cassandra cluster to get a mbean object attribute Livedicsspaceused.
So this Cassandra cluster had 3 node hence different serviceUrl (each having different ip address).
Now I realize that while creating MBeanServerConnectionFactoryBean bean I can specify only one service URl like below:
#Bean
MBeanServerConnectionFactoryBean getConnector() {
MBeanServerConnectionFactoryBean mBeanfactory = new MBeanServerConnectionFactoryBean();
try {
mBeanfactory.setServiceUrl("serviceUrl1");
} catch (MalformedURLException e) {
e.printStackTrace();
}
mBeanfactory.setConnectOnStartup(false);
return mBeanfactory;
}
Then in main I am accessing this as below:
objectName = newObjectName(QueueServicesConstant.MBEAN_OBJ_NAME_LIVE_DISC_USED);
long count = (Long)mBeanFactory.getObject().getAttribute(objectName, QueueServicesConstant.MBEAN_ATTR_NAME_COUNT);
How can i get this value in all three nodes?

You need 3 distinct connectors.
Or you can use something like a Jolokia Proxy to access multiple servers (using REST instead of JSR 160).

This is how I solved the problem ..Instead of using Spring-JMX, I am directly using javax.management apis..So my code below will get any one of the connector which will be sufficient to provide me correct attribute value however it will try to connect to ohther node if it fails to get connector from one server node.
#SuppressWarnings("restriction")
private Object getMbeanAttributeValue(String MbeanObectName,
String attributeName) throws IOException,
AttributeNotFoundException, InstanceNotFoundException,
MBeanException, ReflectionException, MalformedObjectNameException {
Object attributeValue = null;
JMXConnector jmxc = null;
try {
State state = metaTemplate.getSession().getState();
List<String> serviceUrlList = getJmxServiceUrlList(state
.getConnectedHosts());
jmxc = getJmxConnector(serviceUrlList);
ObjectName objectName = new ObjectName(MbeanObectName);
MBeanServerConnection mbsConnection = jmxc
.getMBeanServerConnection();
attributeValue = mbsConnection.getAttribute(objectName,
attributeName);
} finally {
if (jmxc != null)
jmxc.close();
}
return attributeValue;
}
// This will provide any one of the JMX Connector of cassandra cluster
#SuppressWarnings("restriction")
private JMXConnector getJmxConnector(List<String> serviceUrlList)
throws IOException {
JMXConnector jmxc = null;
for (String serviceUrl : serviceUrlList) {
JMXServiceURL url;
try {
url = new JMXServiceURL(serviceUrl);
jmxc = JMXConnectorFactory.connect(url, null);
return jmxc;
} catch (IOException e) {
log.error(
"getJmxConnector: Error while connecting to JMX sereice {} ",
serviceUrl, e.getMessage());
}
}
throw new IOException(
"Not able to connect to any of Cassandra JMX connector.");
}

Related

InstanceNotFoundException when trying to get Activemq MBean

I have the following configuration:
#Configuration
public class ConfigureRMI {
#Value("${jmx.rmi.host:localhost}")
private String rmiHost;
#Value("${jmx.rmi.port:1099}")
private Integer rmiPort;
#Bean
public RmiRegistryFactoryBean rmiRegistry() {
final RmiRegistryFactoryBean rmiRegistryFactoryBean = new RmiRegistryFactoryBean();
rmiRegistryFactoryBean.setPort(rmiPort);
rmiRegistryFactoryBean.setAlwaysCreate(true);
return rmiRegistryFactoryBean;
}
#Bean
#DependsOn("rmiRegistry")
public ConnectorServerFactoryBean connectorServerFactoryBean() throws Exception {
final ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setObjectName("connector:name=rmi");
connectorServerFactoryBean.setServiceUrl(String.format("service:jmx:rmi://%s:%s/jndi/rmi://%s:%s/jmxrmi", rmiHost, rmiPort, rmiHost, rmiPort));
return connectorServerFactoryBean;
}
#Bean
#DependsOn("connectorServerFactoryBean")
public DestinationViewMBean queueMonitor() {
JMXConnectorServer connector = null;
MBeanServerConnection connection;
ObjectName nameConsumers;
try {
connector = connectorServerFactoryBean().getObject();
connection = connector.getMBeanServer();
nameConsumers = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=tasks");
} catch (Exception e) {
e.printStackTrace();
return null;
}
DestinationViewMBean mbView = MBeanServerInvocationHandler.newProxyInstance(connection, nameConsumers, DestinationViewMBean.class, true);
return mbView;
}
}
It configures and instantiates DestinationViewMBean that I try to use later in code like this:
Long queueSize = queueMonitor.getQueueSize();
But it throws an exception javax.management.InstanceNotFoundException: org.apache.activemq:type=Broker,brokerName=localhost,destinationType=Queue,destinationName=tasks
I'm sure the names are as I typed. I can see the brocker name and tasks queue in ActiveMQ web console, elements are queued and dequeued as intended. But I cant't monitor the queue size. The method I used (the one I provided) was made from many answers here on SO and man pages on JMX and ActiveMQ.
I'm wondering if I'm missing something obvious. I turned firewall down, I'm on localhost. Why can't DestinationViewMBean find the queue?
UPD: I used JConsole to check the MBean name. I managed to fix InstanceNotFoundException but now I can't get any attribute from the bean. I've tried a lot of them in debugger (just run throught the attributes I could find in DestinationViewMBean interface). But on every try of attribute getter I get javax.management.AttributeNotFoundException: getAttribute failed: ModelMBeanAttributeInfo not found for QueueSize (or any other attribute).

Using Elasticsearch with jetty jersey

I am using Elastic search, and it works well, but not when I try to use it with a webservice with jetty and jersey.
Here is an example of a function that I want to use :
public boolean insertUser(RestHighLevelClient client, User user) throws IOException
{
java.util.Map<String, Object> jsonMap = new HashMap<String, Object>();
jsonMap.put("username", user.username);
jsonMap.put("password", user.password);
jsonMap.put("mail", user.mail);
jsonMap.put("friends", user.friends);
jsonMap.put("maps", user.maps);
System.out.println("insertUser");
IndexRequest indexRequest = new IndexRequest("users", "doc",user.username)
.source(jsonMap);
try {
IndexResponse indexResponse = client.index(indexRequest);
System.out.println("insertUser 222");
if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
System.out.println("user "+user.username+" créé");
}
else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
System.out.println("user "+user.username+" update dans insertUser (pas normal)");
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
This function works well when I try it inside a test class. But If i start my server like this :
Server server = new Server();
// Add a connector
ServerConnector connector = new ServerConnector(server);
connector.setHost("0.0.0.0");
connector.setPort(8081);
connector.setIdleTimeout(30000);
server.addConnector(connector);
DAO.ClientConnection("0.0.0.0",8081);
// Configure Jersey
ResourceConfig rc = new ResourceConfig();
rc.packages(true, "com.example.jetty_jersey.ws");
rc.register(JacksonFeature.class);
// Add a servlet handler for web services (/ws/*)
ServletHolder servletHolder = new ServletHolder(new ServletContainer(rc));
ServletContextHandler handlerWebServices = new ServletContextHandler(ServletContextHandler.SESSIONS);
handlerWebServices.setContextPath("/ws");
handlerWebServices.addServlet(servletHolder, "/*");
// Add a handler for resources (/*)
ResourceHandler handlerPortal = new ResourceHandler();
handlerPortal.setResourceBase("src/main/webapp/temporary-work");
handlerPortal.setDirectoriesListed(false);
handlerPortal.setWelcomeFiles(new String[] { "homepage.html" });
ContextHandler handlerPortalCtx = new ContextHandler();
handlerPortalCtx.setContextPath("/");
handlerPortalCtx.setHandler(handlerPortal);
// Activate handlers
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[] { handlerWebServices, handlerPortalCtx });
server.setHandler(contexts);
// Start server
server.start();
And when I enter a form, then call this webservice :
#POST
#Path("/signup")
#Produces(MediaType.APPLICATION_JSON)
// #Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public SimpleResponse signup(#Context HttpServletRequest httpRequest,
#FormParam("username") String username,
#FormParam("email") String email,
#FormParam("password") String password,
#FormParam("passwordConfirm") String passwordConfirm) {
System.out.println("k");
//if (httpRequest.getSession().getAttribute("user") != null) { //httpRequest.getUserPrincipal() == null) {
try {
if (password.equals(passwordConfirm)) {
User user = new User("jeanOknewmail#gmail.com", "abc");
user.username = "jeanok";
user.maps = new ArrayList<String>();
user.friends = new ArrayList<String>();
System.out.println(user);
System.out.println("avant insert");
DAO.getActionUser().createIndexUser();
//System.out.println(DAO.getActionUser().getOneUser(DAO.client, "joe"));
System.out.println("rdctfygbhunji,k");
DAO.getActionUser().insertUser(DAO.client, user);
System.out.println("après insert");
return new SimpleResponse(true);
}
} catch (IOException e) {
e.printStackTrace();
}
//}
return new SimpleResponse(false);
}
I get lots of errors :
avax.servlet.ServletException: ElasticsearchStatusException[Unable to parse response body]; nested: ResponseException[method [PUT], host [http://0.0.0.0:8081], URI [/users/doc/jeanok?timeout=1m], status line [HTTP/1.1 404 Not Found]|];
...
Caused by:
ElasticsearchStatusException[Unable to parse response body]; nested: ResponseException[method [PUT], host [http://0.0.0.0:8081], URI [/users/doc/jeanok?timeout=1m], status line [HTTP/1.1 404 Not Found]|];
at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:598)
at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:501)
at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:474)
at org.elasticsearch.client.RestHighLevelClient.index(RestHighLevelClient.java:335)
at DAO.UserDAO.insertUser(UserDAO.java:160)
Do you have any idea why the behaviour of my function isn't the same when I launch my server? And why this error? Thanks for your help
I wasn't connected to elastic search. My client was connected to the wrong port. Now it works

AWS Elasticache Jedis using credentials

I need to connect to a redis instance in my Elasticache. As I understand from Amazon Elasticache Redis cluster - Can't get Endpoint, I can get the endpoint from this.
Now suppose I get the endpoint and I use this endpoint to create a JedisClient(Since I use java) then How do I provide the AWS IAM credentials?
I am going to secure ElastiCache using IAM policies. How do I ensure no other application connects to this redis?
static AWSCredentials credentials = null;
static {
try {
//credentials = new ProfileCredentialsProvider("default").getCredentials();
credentials = new SystemPropertiesCredentialsProvider().getCredentials();
} catch (Exception e) {
System.out.println("Got exception..........");
throw new AmazonClientException("Cannot load the credentials from the credential profiles file. "
+ "Please make sure that your credentials file is at the correct "
+ "location (/Users/USERNAME/.aws/credentials), and is in valid format.", e);
}
}
#Bean
public LettuceConnectionFactory redisConnectionFactory() {
AmazonElastiCache elasticacheClient = AmazonElastiCacheClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)).withRegion(Regions.US_EAST_1).build();
DescribeCacheClustersRequest dccRequest = new DescribeCacheClustersRequest();
dccRequest.setShowCacheNodeInfo(true);
DescribeCacheClustersResult clusterResult = elasticacheClient.describeCacheClusters(dccRequest);
List<CacheCluster> cacheClusters = clusterResult.getCacheClusters();
List<String> clusterNodes = new ArrayList <String> ();
try {
for (CacheCluster cacheCluster : cacheClusters) {
for (CacheNode cacheNode : cacheCluster.getCacheNodes()) {
String addr = cacheNode.getEndpoint().getAddress();
int port = cacheNode.getEndpoint().getPort();
String url = addr + ":" + port;
if(<ReplicationGroup Name>.equalsIgnoreCase(cacheCluster.getReplicationGroupId()))
clusterNodes.add(url);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
LettuceConnectionFactory redisConnectionFactory = new LettuceConnectionFactory(new RedisClusterConfiguration(clusterNodes));
redisConnectionFactory.setUseSsl(true);
redisConnectionFactory.afterPropertiesSet();
return redisConnectionFactory;
}

What is the use of J2C alias on WAS server?

This is my LdapTemplate Class
public LdapTemplate getLdapTemplete(String ldapID)
{
if (ldapID.equalsIgnoreCase(Constants.LDAP1))
{
if (ldapTemplate1 == null)
{
try
{
PasswordCredential passwordCredential = j2cAliasUtility.getAliasDetails(ldapID);
String managerDN = passwordCredential.getUserName();
String managerPwd = new String(passwordCredential.getPassword());
log.info("managerDN :"+managerDN+":: password : "+managerPwd);
LdapContextSource lcs = new LdapContextSource();
lcs.setUrl(ldapUrl1);
lcs.setUserDn(managerDN);
lcs.setPassword(managerPwd);
lcs.setDirObjectFactory(DefaultDirObjectFactory.class);
lcs.afterPropertiesSet();
ldapTemplate1 = new LdapTemplate(lcs);
log.info("ldap1 configured");
return ldapTemplate1;
}
catch (Exception e)
{
log.error("ldapContextCreater / getLdapTemplete / ldap2");
log.error("Error in getting ldap context", e);
}
}
return ldapTemplate1;
}
This is my J2CAliasUtility Class--I dont know what is this method doing and what does it return ?
public PasswordCredential getAliasDetails(String aliasName) throws Exception
{
PasswordCredential result = null;
try
{
// ----------WAS 6 change -------------
Map map = new HashMap();
map.put(com.ibm.wsspi.security.auth.callback.Constants.MAPPING_ALIAS, aliasName); //{com.ibm.mapping.authDataAlias=ldap1}
CallbackHandler cbh = (WSMappingCallbackHandlerFactory.getInstance()).getCallbackHandler(map, null);
LoginContext lc = new LoginContext("DefaultPrincipalMapping", cbh);
lc.login();
javax.security.auth.Subject subject = lc.getSubject();
java.util.Set creds = subject.getPrivateCredentials();
result = (PasswordCredential) creds.toArray()[0];
}
catch (Exception e)
{
log.info("APPLICATION ERROR: cannot load credentials for j2calias = " + aliasName);
log.error(" "+e);
throw new RuntimeException("Unable to get credentials");
}
return result;
}
J2C alias is a feature that encrypts the password used by the adapter to access the database. The adapter can use it to connect to the database instead of using a user ID and password stored in an adapter property.
J2C alias eliminates the need to store the password in clear text in an adapter configuration property, where it might be visible to others.
It would seem that your class "J2CAliasUtility" retrieves a user name and password from an JAAS (Java Authentication and Authorization Service) authentication alias, in this case apparently looked-up from LDAP. An auth alias may be configured in WebSphere Application Server as described here and here. Your code uses WebSphere security APIs to retrieve the user id and password from the given alias. More details on the programmatic logins and JAAS made be found in this IBM KnowledgeCenter topic and it's related topics.

java code to connect weblogic datasource to particular target

I have requirement in which i need to connect to datasource each individual target.
If datsource has two target then i need to connect to both target one by one.
I am using below code for datasource connection.
Need to know how to connect to individual target of datasource
public class ConnectWLSDataSource {
public static void main(String[] args) {
Connection conn;
Statement stmt;
ResultSet rs;
String str1;
try {
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY, “weblogic.jndi.WLInitialContextFactory”);
prop.put(Context.PROVIDER_URL, “t3://HOST_NAME:PORT_NUMBER”);
Context ctx = new InitialContext(prop);
Object obj = ctx.lookup(“DATA_SOURCE_NAME”); // java:comp/env/CPDS
System.out.println(“Data Source Found….”);
DataSource ds = (DataSource) obj;
conn = ds.getConnection();
System.out.println(“Data Source User Name::”+conn.getMetaData().getUserName());
stmt = conn.createStatement();
String query = “select 1 from dual”;
System.out.println(“Query ” + query);
rs = stmt.executeQuery(query);
if (rs != null) {
System.out.println(“Some Data Found in Query”);
} else {
System.out.println(“No Data Found in Query”);
}
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
All you need to do is change the PROVIDER_URL to the specific host you want. For instance we have 4 servers running in a cluster and can choose to use a load balancer if we want to round-robin the connections or we can pick one specific server in the cluster.
we face issue when using this code, and get below exception. in all if 100 requests are serviced one fails with the below exception.
javax.naming.CommunicationException [Root exception is java.net.ConnectException: t3://prod.abc.com:7114: Destination unreachable; nested exception is:
java.net.SocketTimeoutException: Read timed out; No available router to destination].

Resources