Checking domain name age through Java - java

I am making a simple phishing scanner tool for a university project. One of my detection methods includes checking if the DNS within the email are valid, and I also want to check their age. This is example code of how I check if they are existing:
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import java.util.Hashtable;
public class DNSExample {
static int doLookup( String hostName ) throws NamingException {
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial",
"com.sun.jndi.dns.DnsContextFactory");
DirContext ictx = new InitialDirContext( env );
Attributes attrs =
ictx.getAttributes( hostName, new String[] { "MX" });
Attribute attr = attrs.get( "MX" );
if( attr == null ) return( 0 );
return( attr.size() );
}
public static void main( String args[] ) {
String [] array = {"google.com","dsad33114sssaxzx.com"} ;
for( int i = 0; i < array.length; i++ ) {
try {
System.out.println( array[i] + " has " +
doLookup( array[i] ) + " mail servers" );
}
catch( Exception e ) {
System.out.println(array[i] + " : " + e.getMessage());
}
}
}
}
How would I need to modify the above code to include a check of age
for servers that exist?

I think you've chosen a problem that cannot be solved in the general case ... using current generation internet standards:
The information you need cannot be obtained from DNS itself.
In some cases information about DNS registrations can be obtained from WHOIS. However, the information returned by WHOIS servers is not standardised:
There is no standard information model.
There is no standard format.
There are no guarantees as to the accuracy of the information.
It is not even clear if "age of server" is going to be available. (For instance, the closest that APNIC's WHOIS provides to that is the last modification timestamp for the DNS record. And that is NOT a good proxy for server age.)
There is a set of RFC's that define something called CRISP, but as far as I can make out the purpose of that standard is for registrar to registrar exchange of information. (I couldn't find any public-facing services based on CRISP.)
There is also an IETF working group called WEIRDS which I think is intended to define a web-enabled replacement for WHOIS. (Don't confuse WEIRDS with the IETF WEIRD WG!) But that was formed very recently, and it is too soon to make any predictions of the outcome. (Or how long it will take for the NICs to implement any specs that come out of the WG.)
Summary: your chances of implementing something in this space that really works are currently low. Probably the best you can hope to achieve is something based on screen-scraping one or two WHOIS services.
This might change in a few years, but that is of no help for your current project.

It seems based on your description and comments above you are trying to gather whois information.
download APIs from http://commons.apache.org/proper/commons-net/
change the nameToQuery below and run it.
public class WhoisIt {
public static final String WHOIS_SERVER = "whois.internic.net";
public static final int WHOIS_PORT = 43;
public static void main(String[] args) throws Exception {
String nameToQuery = "avajava.com";
WhoisClient whoisClient = new WhoisClient();
whoisClient.connect(WHOIS_SERVER, WHOIS_PORT);
String results = whoisClient.query(nameToQuery);
System.out.println(results);
}
}
good luck

Related

Logging with optional parameters

I have method where I want to add specific logging:
#Slf4j
#Service
public class SomethingService {
public void doSomething(Something data, String comment, Integer limit) {
Long id = saveSomethingToDatabase(data, comment);
boolean sentNotification = doSomething(id);
// ...
// Log what you done.
// Variables that always have important data: data.getName(), id
// Variables that are optional: sentNotification, comment, limit
// (optional means they aren't mandatory, rarely contains essential data, often null, false or empty string).
}
}
I can simply log all:
log.info("Done something '{}' and saved (id {}, sentNotification={}) with comment '{}' and limit {}",
something.getName(), id, sentNotification, comment, limit);
// Done something 'Name of data' and saved (id 23, sentNotification=true) with comment 'Comment about something' and limit 2
But most of the time most of the parameters are irrelevant. With the above I get logs like:
// Done something 'Name of data' and saved (id 23, sentNotification=false) with comment 'null' and limit null
That makes logs hard to read, long and unnecessarily complicated (in most cases other parameters aren't present).
I want to handle all cases with preserving only essential data. Examples:
// Done something 'Name of data' and saved (id 23)
// Done something 'Name of data' and saved (id 23) with comment 'Comment about something'
// Done something 'Name of data' and saved (id 23) with limit 2
// Done something 'Name of data' and saved (id 23) with comment 'Comment about something' and limit 2
// Done something 'Name of data' and saved (id 23, sent notification)
// Done something 'Name of data' and saved (id 23, sent notification) with limit 2
// Done something 'Name of data' and saved (id 23, sent notification) with comment 'Comment about something'
// Done something 'Name of data' and saved (id 23, sent notification) with comment 'Comment about something' and limit 2
I can code it by hand:
String notificationMessage = sentNotification ? ", sent notification" : "";
String commentMessage = comment != null ? String.format(" with comment '%s'", comment) : "";
String limitMessage = "";
if (limit != null) {
limitMessage = String.format("limit %s", limit);
limitMessage = comment != null ? String.format(" and %s", limitMessage) : String.format(" with %s", limitMessage);
}
log.info("Done something '{}' and saved (id {}{}){}{}",
something.getName(), id, notificationMessage, commentMessage, limitMessage);
But it's hard to write, hard to read, complicated and causes errors.
I would like something like specify part of logs.
Example pseudocode:
log.info("Done something '{}' and saved (id {} $notification) $parameters",
something.getName(), id,
$notification: sentNotification ? "sent notification" : "",
$parameters: [comment, limit]);
It should supports optional parameters, replace boolean/condition with given string, supports separating spaces, commas and words with and and.
Maybe are there existing library for this? Or maybe is there at least a simpler way for coding this?
If not, it remains for me nothing else to write my own library for messages to logging. Additionally, this kind of library will provide that all logs would be consistent.
If you don't see a problem with three optional parameters, just imagine there are more (and you can't always pack them into a class - another class layer only for parameter logging cause even more complications).
At the end, I know I can log each action separately. But with this I get many more logs and I won't have the most important information in one place. Other logs are in the debug level, not info.
both of these are possible. You can either:
register a component with the Logger to do the work for you
write a wrapper class for your logger to use
I will demonstrate both and explain why I think the second is the better choice. Let's start with that:
Instead of having the Logger own the knowledge of how to format your specific properties, let your code own this responsibility.
For example, rather than logging each parameter, collect them and define their logging separately. See this code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggingExample {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggingExample.class);
public static void main(String[] args) {
LogObject o = new LogObject();
LOGGER.info("{}", o);
o.first = "hello";
LOGGER.info("{}", o);
o.second = "World";
LOGGER.info("{}", o);
o.last = "And finally";
LOGGER.info("{}", o);
}
public static class LogObject {
String first;
String second;
String last;
#Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Log Object: ");
if (first != null) {
buffer.append("First: " + first + " ");
}
if (second != null) {
buffer.append("Second: " + second + " ");
}
if (last != null) {
buffer.append("Second: " + last + " ");
}
return buffer.toString();
}
}
}
We define LogObject as a container and this container implements toString. All Loggers will call toString() on their objects, that is how they figure out what they should print (unless special formatters applied etc).
With this, the log statements print:
11:04:12.465 [main] INFO LoggingExample - Log Object:
11:04:12.467 [main] INFO LoggingExample - Log Object: First: hello
11:04:12.467 [main] INFO LoggingExample - Log Object: First: hello Second: World
11:04:12.467 [main] INFO LoggingExample - Log Object: First: hello Second: World Second: And finally
Advantages:
this works with any Logger. You won't have to implement specifics depending on what you want to use
the knowledge is encapsulated in 1 object that can be easily tested. This should mitigate the error prone formatting problem you stated.
no need for a complex formatter library or implementation
It will make the logging look much nicer and compact in the end. log.info("{}", object);
Disadvantage:
You are required to write the Bean.
Now the same can be achieved using for example a custom Layout. I am using logback, so this is an example for logback.
We may define a Layout that owns the knowledge of what to do with your custom formatting instructions.
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.ConsoleAppender;
import ch.qos.logback.core.LayoutBase;
public class LoggingExample2 {
private static final Logger CUSTOM_LOGGER = createLoggerFor("test");
public static void main(String[] args) {
LogObject o = new LogObject();
CUSTOM_LOGGER.info("{}", o);
o.first = "hello";
CUSTOM_LOGGER.info("{}", o);
o.second = "World";
CUSTOM_LOGGER.info("{}", o);
o.last = "And finally";
CUSTOM_LOGGER.info("{}", o);
}
public static class LogObject {
String first;
String second;
String last;
#Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Log Object: ");
if (first != null) {
buffer.append("First: " + first + " ");
}
if (second != null) {
buffer.append("Second: " + second + " ");
}
if (last != null) {
buffer.append("Second: " + last + " ");
}
return buffer.toString();
}
}
public static class ModifyLogLayout extends LayoutBase<ILoggingEvent> {
#Override
public String doLayout(ILoggingEvent event) {
String formattedMessage = event.getFormattedMessage() + "\n";
Object[] args = event.getArgumentArray();
return String.format(formattedMessage, args);
}
}
private static Logger createLoggerFor(String string) {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
PatternLayoutEncoder ple = new PatternLayoutEncoder();
ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
ple.setContext(lc);
ple.start();
ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<ILoggingEvent>();
consoleAppender.setEncoder(ple);
consoleAppender.setLayout(new ModifyLogLayout());
consoleAppender.setContext(lc);
consoleAppender.start();
Logger logger = (Logger) LoggerFactory.getLogger(string);
logger.addAppender(consoleAppender);
logger.setLevel(Level.DEBUG);
logger.setAdditive(false); /* set to true if root should log too */
return logger;
}
}
I borrowed the Logger instatiation from: Programmatically configure LogBack appender
Note that I have not found a library that can parse the complex expressions that you have listed. I think you may have to write your own implementation.
In my example, i only illustrate how to intercept and modify the message based on the arguments.
Why I would not recommend this unless it is really needed:
the implementation is specific to logback
writing correct formatting is hard ... it will produce more errors than creating a custom object to format
It is harder to test because you literally have unlimited objects that may pass through this (and formatting). Your code must be resilient to this now, and in the future since any developer may add the weirdest things at any time.
The last (unasked) answer:
Why don't you use a json encoder? And then use something like logstash to aggregate (or cloudlwatch, or anything else).
This should solve all your problems.
This is what I have done in the past:
Define 1 bean that you like to log "differently". I call it metadata. This bean can be i.e.
public class MetaHolder {
// map holding key/values
}
This basically just stores all your variables with a key. It allows you to effectively search on these keys, sink them into databases, etc. etc.
In your log, you simply do:
var meta = // create class
meta.put("comment", comment);
// put other properties here
log.info("formatted string", formattedArguments, meta); // meta is always the last arg
In the Layout this can then be converted quite nicely. Because you are no longer logging "human language", there are no "withs" and "in" to replace. Your log will simply be:
{
"time" : "...",
"message" : "...",
"meta" : {
"comment" : "this is a comment"
// no other variables set, so this was it
}
}
And one last (last) one in just pure java, if you wanted that. You could write:
public static void main(String[] args) {
String comment = null;
String limit = "test";
String id = "id";
LOGGER.info(
"{} {} {}",
Optional.ofNullable(comment).map(s -> "The comment " + s).orElse(""),
Optional.ofNullable(limit).map(s -> "The Limit " + s).orElse(""),
Optional.ofNullable(id).map(s -> "The id " + s).orElse(""));
}
Which effectively moves the conditional logic you want in your formatting into Java's Optional.
I find this also is hard to read and test and would still recommend the first solution

How can I access the text of the SMS sent thru Twilio to my Spring Boot Controller?

I'm trying to use Twilio to receive SMS messages, and use the body of the SMS to perform various DB functions. The part where I'm stuck is parsing the message that I get from Twilio when they receive a text message.
Here's the controller:
#RequestMapping(
value = "/incomingSMS",
method = RequestMethod.POST)
public void getPhrase(#RequestBody String request) {
System.out.println("***********************************");
System.out.println(request);
System.out.println("***********************************");
}
And here's what is getting printed out (with new lines added for readability, and some numbers censored.):
ToCountry=US&
ToState=statecode&
SmsMessageSid=smsMessageSid&
NumMedia=0&
ToCity=city&
FromZip=zipCode&
SmsSid=SmsSid&
FromState=statecode&
SmsStatus=received&
FromCity=city&
Body=Hello+it%27s+John+&
FromCountry=US&
To=%2B1toPhoneNumber&
ToZip=55401&
NumSegments=1&
MessageSid=messageSid&
AccountSid=accountSid&
From=%2B1fromPhoneNumber&
ApiVersion=2010-04-01
I can see in "Body" my message is hiding. I also see the phone number. Is there any way I can just parse this into a Twilio object that I don't know about, so I can use methods like getBody(), getFrom()?
You can easily manipulate it by using the good old java.util.Properties class.
For the example bellow, I'm using the Apache Common IO lib to transform the String into an InputStream witch is required by Properties class. After that, all you have to do is use getProperty method to get what you need.
package com.pipocandobits.maven;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.util.Properties;
public class App {
public static void main( String[] args ) throws IOException {
System.out.println( "Hello World!" );
String source = "ToCountry=US&\n" +
"ToState=statecode&\n" +
"SmsMessageSid=smsMessageSid&\n" +
"NumMedia=0&\n" +
"ToCity=city&\n" +
"FromZip=zipCode&\n" +
"SmsSid=SmsSid&\n" +
"FromState=statecode&\n" +
"SmsStatus=received&\n" +
"FromCity=city&\n" +
"Body=Hello+it%27s+John+&\n" +
"FromCountry=US&\n" +
"To=%2B1toPhoneNumber&\n" +
"ToZip=55401&\n" +
"NumSegments=1&\n" +
"MessageSid=messageSid&\n" +
"AccountSid=accountSid&\n" +
"From=%2B1fromPhoneNumber&\n" +
"ApiVersion=2010-04-01";
Properties properties = new Properties();
properties.load(IOUtils.toInputStream(source, "UTF-8"));
System.out.println("Message body = " + properties.getProperty("Body"));
}
}
For more on how to use the java.util.Properties class check this link https://www.tutorialspoint.com/java/java_properties_class.htm

Mapping characters to keycodes for international keysets

so I built a pi zero keyboard emulator as mentioned here:
https://www.rmedgar.com/blog/using-rpi-zero-as-keyboard-setup-and-device-definition
I make it type text that it reads from a local text-file (everything developed in java - for reasons :) ).
My problem now is that the configured keysets on the various computers my pi zero is attached to differ very much (german, english, french, ...). Depending on the computer this leads to several typing mistakes (e.g., z instead of y).
So I now built some "translation tables" that map characters to the keycodes fitting to the computer. Such a table looks like this:
public scancodes_en_us() {
//We have (Character, (scancode, modifier))
table.put("a",Pair.create("4","0"));
table.put("b",Pair.create("5","0"));
table.put("c",Pair.create("6","0"));
table.put("d",Pair.create("7","0"));
table.put("e",Pair.create("8","0"));
table.put("f",Pair.create("9","0"));
table.put("g",Pair.create("10","0"));
table.put("h",Pair.create("11","0"));
table.put("i",Pair.create("12","0"));
table.put("j",Pair.create("13","0"));
table.put("k",Pair.create("14","0"));
table.put("l",Pair.create("15","0"));
table.put("m",Pair.create("16","0"));
table.put("n",Pair.create("17","0"));
table.put("o",Pair.create("18","0"));
table.put("p",Pair.create("19","0"));
table.put("q",Pair.create("20","0"));
table.put("r",Pair.create("21","0"));
table.put("s",Pair.create("22","0"));
table.put("t",Pair.create("23","0"));
table.put("u",Pair.create("24","0"));
table.put("v",Pair.create("25","0"));
table.put("w",Pair.create("26","0"));
table.put("x",Pair.create("27","0"));
table.put("y",Pair.create("28","0"));
table.put("z",Pair.create("29","0"));
table.put("A",Pair.create("4","2"));
table.put("B",Pair.create("5","2"));
table.put("C",Pair.create("6","2"));
table.put("D",Pair.create("7","2"));
table.put("E",Pair.create("8","2"));
table.put("F",Pair.create("9","2"));
table.put("G",Pair.create("10","2"));
table.put("H",Pair.create("11","2"));
table.put("I",Pair.create("12","2"));
table.put("J",Pair.create("13","2"));
table.put("K",Pair.create("14","2"));
table.put("L",Pair.create("15","2"));
table.put("M",Pair.create("16","2"));
table.put("N",Pair.create("17","2"));
table.put("O",Pair.create("18","2"));
table.put("P",Pair.create("19","2"));
table.put("Q",Pair.create("20","2"));
table.put("R",Pair.create("21","2"));
table.put("S",Pair.create("22","2"));
table.put("V",Pair.create("25","2"));
table.put("W",Pair.create("26","2"));
table.put("X",Pair.create("27","2"));
table.put("Y",Pair.create("28","2"));
table.put("Z",Pair.create("29","2"));
table.put("1",Pair.create("30","0"));
table.put("2",Pair.create("31","0"));
table.put("5",Pair.create("34","0"));
table.put("6",Pair.create("35","0"));
table.put("7",Pair.create("36","0"));
table.put("8",Pair.create("37","0"));
table.put("9",Pair.create("38","0"));
table.put("0",Pair.create("39","0"));
table.put("!",Pair.create("30","2"));
table.put("#",Pair.create("31","2"));
table.put("#",Pair.create("32","2"));
table.put("$",Pair.create("33","2"));
table.put("%",Pair.create("34","2"));
table.put("^",Pair.create("35","2"));
table.put("&",Pair.create("36","2"));
table.put("*",Pair.create("37","2"));
table.put("(",Pair.create("38","2"));
table.put(")",Pair.create("39","2"));
table.put(" ",Pair.create("44","0"));
table.put("-",Pair.create("45","0"));
table.put("=",Pair.create("46","0"));
table.put("[",Pair.create("47","0"));
table.put("]",Pair.create("48","0"));
table.put("\\",Pair.create("49","0"));
table.put(";",Pair.create("51","0"));
table.put("'",Pair.create("52","0"));
table.put("`",Pair.create("53","0"));
table.put(",",Pair.create("54","0"));
table.put(".",Pair.create("55","0"));
table.put("/",Pair.create("56","0"));
table.put("_",Pair.create("45","2"));
table.put("+",Pair.create("46","2"));
table.put("{",Pair.create("47","2"));
table.put("}",Pair.create("48","2"));
table.put("|",Pair.create("49","2"));
table.put(":",Pair.create("51","2"));
table.put("\"",Pair.create("52","2"));
table.put("~",Pair.create("53","2"));
table.put("<",Pair.create("54","2"));
table.put(">",Pair.create("55","2"));
table.put("?",Pair.create("56","2"));
Having such a table for many different keyboard layouts is a pain. Is there some more clever version to map a character to the scancode for a specific keyboard layout?
If not - is there some kind of archive where I can find such a character to scancode mapping for many different keyboard layouts?
Thank you very much
Look at how localization works, they all share the same approach: Create a special version for each localization as a property file, then have an abstract class to load the property based on locale.
You will develop a loader class like this:
public scancodes(Locale locale) {
// load locale property file or download if missing
// read the property and store to the table
ResourceBundle scanCodes = ResourceBundle.getBundle("codes",locale);
}
And your codes_locale looks like:
codes_de.properties
a=4,0
b=5,0
By doing this, you separate the locale specific character with your logic code, and you don't need to bundle all keyboards in side your app. You can download them as needed.
You can access a tutorial here
If I understood what you are trying to do correctly then you don't have to map anything at all, just use a pre-made format (like unicode which works for all languages I know of), just send a char code and translate it to it's matching char.
Example file reader - char interpreter:
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.showOpenDialog(null);
File textFile = fc.getSelectedFile();
if(textFile.getName().endsWith(".txt")) {
System.out.println(textFile.getAbsolutePath());
FileInputStream input = new FileInputStream(textFile);
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UNICODE"));
char[] buffer = new char[input.available() / 2 - 1];
System.out.println("Bytes left: " + input.available());
int read = reader.read(buffer);
System.out.println("Read " + read + " characters");
for(int i = 0; i < read; i++) {
System.out.print("The letter is: " + buffer[i]);
System.out.println(", The key code is: " + (int) buffer[i]);
}
}
you can later use the key code to emulate a key press on your computer
For scan-code mappings you can visit following sites:
Keyboard scancodes
Scan Codes Demystified
My solution is to determine the list of keycode on runtime, it'll save you a lot of caffeine and headache
package test;
import java.util.HashMap;
import java.util.Map;
import javax.swing.KeyStroke;
public class Keycode {
/**
* List of chars, can be stored in file
* #return
*/
public String getCharsets() {
return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSVWXYZ12567890!##$%^&*() -=[]\\;'`,./_+{}|:\\~<>?";
}
/**
* Determines the keycode on runtime
* #return
*/
public Map<Character, Integer> getScancode() {
Map<Character, Integer> table = new HashMap<>();
String charsets = this.getCharsets();
for( int index = 0 ; index < charsets.length() ; index++ ) {
Character currentChar = charsets.charAt(index);
KeyStroke keyStroke = KeyStroke.getKeyStroke(currentChar.charValue(), 0);
// only for example i've used Map, but you should populate it by your table
// table.put("a",Pair.create("4","0"));
table.put(currentChar, keyStroke.getKeyCode());
}
return table;
}
public static void main(String[] args) {
System.out.println(new Keycode().getScancode());
}
}

How to get an Initial Contex from Wildfly 8

ADDED 7/23.
Many views: Not even a "that's dumb" question in response. Can anyone at least tell me why such an embarrassingly trivial question seems to have no answer anywhere.
Q:
--- Have Wildfly 8 running on local machine localhost:9990.
--- Have a Java program that need's Wildfly's IntialContext.
--- Every reference says use: "Context ctx = new InitialContext(env);"
--- Yet a week of searching turns up no set of properties that returns one.
And no example of a java program that gets one.
Does no one ever do this? Really need help
Original Msg Below
I know many people have asked how to get an Initial context from Wildfly 8. But I have yet to find a simple answer with a simple example.
Therefore, I hope someone can tell my why this doesn’t work.
I start Wildfly with standalone-full.xml
The three sections below have
A - Code summary of my test Class whose only purpose is to secure an Initial Context. (I only removed a lot of printing code that produced the next section.]
B - The Eclipse console output for a failure.
C - Cut and paste code. Just in case anyone can help me get this to work. I’d like to leave behind something the next new WF user can cut and past and run. The only difference from 1 above is that this version has all the static methods I used to format the output. NOTE: I know the comments I inserted about the less than sign sound dumb. BUT ... they are true.
A Code Summary
import java.util.Properties;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.InitialContext;
public class JmsTestGetJNDIContext {
//members
final private Properties env = new Properties() {
private static final long serialVersionUID = 1L;
{
/* These are Properties used by a standalone JavaClient to secure a WIldFly InitialContext()*/
put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
put(Context.PROVIDER_URL,"http-remoting://localhost:9990");
put(Context.SECURITY_PRINCIPAL,"userGLB");
put(Context.SECURITY_CREDENTIALS,"Open");
put("jboss.naming.client.ejb.context", true);
/*The above URL, ID and PW successfully open Wildfly's Admin Console*/
}
};
//constructor
private JmsTestGetJNDIContext (){
/*print "beg"*/
/*print "env"*/
try {
/*print "Requesting InitialContext"*/
Context ctx = new InitialContext(this.env);
/*print "JNDI Context: " + ctx)*/
/*print "end");
} catch (CommunicationException e) {
/* print "You forgot to start WildFly dummy!"*/
} catch (Exception e) {
/* print"caught: " + e.getClass().getName()*/
/*print e.getMessage()*/
/* "end")*/
}
static public void main (String[] args) {
/*print "beg"*/
JmsTestGetJNDIContext client = new JmsTestGetJNDIContext ();
/*print "end"*/
}
}
B - Console Output
JmsTestGetJNDIContext.main () beg
JmsTestGetJNDIContext.<init> () beg
JmsTestGetJNDIContext.<init> () These are Properties used to obtain IntialContext
Key: java.naming.provider.url
Value: http-remoting://localhost:9990
Key: java.naming.factory.initial
Value: org.jboss.naming.remote.client.InitialContextFactory
Key: jboss.naming.client.ejb.context
Value: true
Key: java.naming.security.principal
Value: userGLB
Key: java.naming.security.credentials
Value: Open
JmsTestGetJNDIContext.<init> () Requesting InitialContext
JmsTestGetJNDIContext.<init> () caught: javax.naming.NamingException
JmsTestGetJNDIContext.<init> () Failed to create remoting connection
JmsTestGetJNDIContext.<init> () end
JmsTestGetJNDIContext.main () end
Cut and Paste Code
package org.america3.gotest.xtra;
import java.util.Properties;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.InitialContext;
public class JmsTestGetJNDIContext {
//members
final private Properties env = new Properties() {
/**
* Properties used by a standalone JavaClient to secure
* a WIldFly InitialContext()*/
private static final long serialVersionUID = 1L;
{
put(Context.INITIAL_CONTEXT_FACTORY,"org.jboss.naming.remote.client.InitialContextFactory");
put(Context.PROVIDER_URL, "http-remoting://localhost:9990");
put(Context.SECURITY_PRINCIPAL, "userGLB");
put(Context.SECURITY_CREDENTIALS, "Open");
// The above URL, ID and PW successfully open Wildfly's Admin Console
put("jboss.naming.client.ejb.context", true);
}
};
//constructor
private JmsTestGetJNDIContext (){/*ignore*/String iAm = JmsTestGetJNDIContext.getIAm(" ", Thread.currentThread().getStackTrace());
P (iAm, "beg");
pProps(iAm, env);
try {
P (sp + iAm, "Requesting InitialContext");
Context ctx = new InitialContext(this.env);
P (sp + iAm, "JNDI Context: " + ctx);
P (sp + iAm, "end");
} catch (CommunicationException e) {
P (sp + iAm, "You forgot to start WildFly dummy!");
} catch (Exception e) {
P (sp + iAm, "caught: " + e.getClass().getName());
P (sp + iAm, e.getMessage());
P (iAm, "end");
}
}
static public void main (String[] args) {/*ignore*/String iAm = JmsTestGetJNDIContext.getIAm("",Thread.currentThread().getStackTrace());
P (iAm, "beg");
JmsTestGetJNDIContext client = new JmsTestGetJNDIContext ();
P (iAm , "end");
}
/*The remaining static methods are just to facilitate printing.
* They are normally in a Untility package I add to my projects.
* I put them here so this code would run for anyone.*/
static private void pProps (String leader, Properties p) {
StringBuffer sb = new StringBuffer ();
String s = JmsTestGetJNDIContext.padRight(leader, 45, ' ');
s = " " + s + "These are Properties used to obtain IntialContext"+"\n";
sb.append(s);
String skip = "";
for (Object key: p.keySet()) {
sb.append(skip + " " + JmsTestGetJNDIContext.padRight("\""
+ (String)key + "\"", 40, ' ')
+ " \"" + p.get(key) + "\"");
skip = "\n";
}
System.out.println(sb);
}
static private void P (String s, String s2) {
System.out.println(s + s2);
}
static public String getClassMethodName (StackTraceElement[] elements) {
String className = null;
for (int i = 0; i * elements.length; i++]i ) {
/* You need to type in a less than sign for the '*'
* because when I do, the editor will not show any code
* that comes after it.
* I have no idea why, but I've spent over an hour trying,
* and every time I type a less than sign all the following
* code dissappears!*/
className = elements[i].getClassName ();
if (className.startsWith ("org.america3")) {
int end = className.lastIndexOf ('.');
return className.substring (end + 1) + "." + elements[i].getMethodName ();
} else {
continue;
}
}
return "no project method found in elements beginning with org.america3" ;
}
static private String getIAm (String indent, StackTraceElement[] elements) {
StringBuffer sb = new StringBuffer ();
sb.append(JmsTestGetJNDIContext.getClassMethodName(elements));
sb.append(" ()");
return indent + JmsTestGetJNDIContext.padRight (sb.toString(), 45, ' ') ;
}
static public String padRight(String s, int width, char c){
if (s == null) return "Null String";
if(s.length() ** width){
/* You need to type in a greater than or equal sign for
* the '**'see above.*/
return s;
} else {
StringBuffer sb = new StringBuffer();
sb.append (s);
for(int i = 0; i *** (width - s.length()); i++){
/*You need to type in a less than sign the '***'. Again see above*/
sb.append(c);
}
return sb.toString();
}
}
static public String sp = " ";
}
A while ago I also struggled with remote EJBs in my CLI application. I excavated a small example project that I wrote then. It gets an InitialContext and calls a remote EJB named AddBrackets:
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import de.dnb.test.ejb.AddBrackets;
public final class Application {
public static void main(String[] args) throws NamingException {
final Properties jndiProperties = initJndiProperties();
final AddBrackets addBrackets = getEjb(jndiProperties);
System.out.println(addBrackets.processText("Hello World"));
}
private static Properties initJndiProperties() {
final Properties jndiProperties = new Properties();
jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jboss.naming.remote.client.InitialContextFactory");
jndiProperties.put("jboss.naming.client.ejb.context", true);
jndiProperties.put(Context.PROVIDER_URL, "http-remoting://localhost:8080/");
//jndiProperties.put(Context.SECURITY_PRINCIPAL, "test");
//jndiProperties.put(Context.SECURITY_CREDENTIALS, "test");
return jndiProperties;
}
private static AddBrackets getEjb(Properties jndiProps)
throws NamingException {
final Context jndiContext = new InitialContext(jndiProps);
final String interfaceName = AddBrackets.class.getName();
return (AddBrackets) jndiContext.lookup(
"ejbtest-app-1.0-SNAPSHOT/ejbtest-ejb-1.0-SNAPSHOT/AddBracketsBean!"
+ interfaceName);
}
}
I built this program as a Maven project which had a dependency on
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-ejb-client-bom</artifactId>
<version>8.2.1.Final</version>
<type>pom</type>
</dependency>
This dependency brings in Wildfly's remote client EJB implementation and adds the following jars to the class path (links are to Maven Central):
jboss-logging-3.1.4.GA.jar
jboss-marshalling-1.4.9.Final.jar
jboss-marshalling-river-1.4.9.Final.jar
jboss-remoting-4.0.7.Final.jar
jboss-sasl-1.0.4.Final.jar
jboss-ejb-api_3.2_spec-1.0.0.Final.jar
jboss-transaction-api_1.2_spec-1.0.0.Final.jar
xnio-api-3.3.0.Final.jar
xnio-nio-3.3.0.Final.jar
jboss-ejb-client-2.0.1.Final.jar
jboss-remote-naming-2.0.1.Final.jar
wildfly-build-config-8.2.1.Final.jar
I did no special configuration on Wildfly to run this example. I simply downloaded a vanilla Wildfly 8.2.1, unzipped it, set up an admin user with the add-user.sh script and deployed my EJB in an EAR. As you can see above access is granted without a username and a password.
You can find the complete project including the AddBrackets EJB on my bitbucket account.
When I tried to get my head around remote EJBs with Wildfly, I found the article JBoss EAP / Wildfly – Three ways to invoke remote EJBs really helpful. It clearly describes the three different methods to access remote EJBs on Wildfly.
According to your own answer the following jars are on your classpath:
jboss-remote-naming-1.0.7.final.jar
jboss-logging.jar
xnio-api-3.0.7.ga.jar
jboss-remoting-3.jar
jboss-ejb-client-1.0.19.final.jar
You write that the application throws the following exception:
java.lang.NoSuchMethodError:
org.jboss.remoting3.Remoting.createEndpoint(Ljava/lang/String;Lorg/xnio/OptionMap;)Lorg/jboss/remoting3/Endpoint;]
This exception is thrown when org.jboss.naming.remote.client.EndpointCache which is part of the jboss-remote-naming jar tries to call Remoting.createEndpoint() which is contained in the jboss-remoting jar.
As you explain in your answer the reason for this is that the Remoting class declares a 3-parameter version of the createEndpoint() method while the EndpointCache class tries to call a 2-parameter version which does not exist.
I checked the commit histories and declared dependencies of the jboss-remote-naming and the jboss-remoting projects to find out what is going wrong there. This is what I found out:
The 2-parameter version of createEndpoint() was only added in version 3.2 of jboss-remoting. The pom.xml for jboss-remote-naming-1.0.7.final says it depends on jboss-remoting 3.2.7.GA.
As there is no version number on your jboss-remoting-3.jar, I guess it is an older version. You should be able to check this by looking for a pom.xml in META-INF folder of your jboss-remoting-3.jar. This should contain the version number.
To solve your problem, I suggest to replace your jboss-remoting-3.jar with jboss-remoting-3.2.7ga.jar or to use the set of jars I listed in my other answer.
I’ve decided the problem isn’t coding or the JNDI InititialContext Properties.
I mean the fatal error is a NoSuchMethodError. Therefore, as I confirmed in the WildFly server logs, my main method never even tries to connect.
Here’s what I think explains the real problem.
And I think it explains why there are so many calls for help with this error:
java.lang.NoSuchMethodError:
org.jboss.remoting3.Remoting.createEndpoint(Ljava/lang/String;Lorg/xnio/OptionMap;)Lorg/jboss/remoting3/Endpoint;]
Also why none of those calls for help ever get a conclusive answer. Just people suggesting different jars.
And since all those answers fixed on jars, this is how I tested the Build Path I was using:
First I removed all jars from the Build Path. Then I ran my one line main program till all ClassNotFoundException were gone.
First Error
java.lang.ClassNotFoundException:
org.jboss.naming.remote.client.InitialContextFactory]
Added jboss-remote-naming-1.0.7.final.jar to class path
Next Error
java.lang.NoClassDefFoundError:
org/jboss/logging/Logger
Added jboss-logging.jar
Next Error
java.lang.NoClassDefFoundError:
org/xnio/Options
Added xnio-api-3.0.7.ga.jar
Next Error
java.lang.NoClassDefFoundError:
org/jboss/remoting3/spi/ConnectionProviderFactory
Added jboss-remoting-3.jar
Next Error
java.lang.NoClassDefFoundError:
org/jboss/ejb/client/EJBClientContextIdentifier
Added jboss-ejb-client-1.0.19.final.jar
FATAL ERROR (note: All NoClassDefFoundError have been cleared)
java.lang.NoSuchMethodError:
org.jboss.remoting3.Remoting.createEndpoint(Ljava/lang/String;Lorg/xnio/OptionMap;)Lorg/jboss/remoting3/Endpoint;]
Then I used Eclipse’s Project Explorer to verify:
That jboss-remoting3.jar has the org.jboss.remoting3.Remoting Class. It does. That’s why there is no NoClassDefFoundError left above.
And verified it had this method:
public Endpoint createEndpoint (String, Executor, OptionMap) note: 3 parameters.
BUT the above Error indicates something is calling:
public Endpoint createEndpoint (String, OptionMap) note: 2 parameters.
That’s why the program throws a NoSuchMethodError. It is looking for a 2 paramater version of org.jboss.remoting3.Remoting.createEndpoint(). And the Remoting Class I have only has a 3 parameter version.`
I know this sounds impossible but the only thing I can think is there is an inconsistency in the Java API???
Clearly something is calling org.jboss.remoting3.Remoting.createEndpoint with 2 parameters.
But my org.jboss.remoting3.Remoting Class only has a 3 parameter version of the createEndpoint() Method.
So I’m going to clean this all up and repost a question asking how to explain the existence of a Class calling for a 2 paramter org.jboss.remoting3.Remoting.createEndpoint Method when I have a jar whose org.jboss.remoting3.Remoting only offers a 3-parameter.
Here is your obligatory "that's a dumb question." Does the wildfly remote quickstart github repo answer the question for you? Their code, from RemoteEJB.java
final Hashtable<String, String> jndiProperties = new Hashtable<>();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
final Context context = new InitialContext(jndiProperties);
return (RemoteCalculator) context.lookup("ejb:/ejb-remote-server-side/CalculatorBean!" + RemoteCalculator.class.getName());

How do I access Windows Event Viewer log data from Java

Is there any way to access the Windows Event Log from a java class. Has anyone written any APIs for this, and would there be any way to access the data from a remote machine?
The scenario is:
I run a process on a remote machine, from a controlling Java process.
This remote process logs stuff to the Event Log, which I want to be able to see in the controlling process.
Thanks in advance.
http://www.j-interop.org/ is an open-source Java library that implements the DCOM protocol specification without using any native code. (i.e. you can use it to access DCOM objects on a remote Windows host from Java code running on a non-Windows client).
Microsoft exposes a plethora of system information via Windows Management Instrumentation (WMI). WMI is remotely accessible via DCOM, and considerable documentation on the subject exists on Microsoft's site. As it happens, you can access the Windows Event Logs via this remotely accessible interface.
By using j-interop you can create an instance of the WbemScripting.SWbemLocator WMI object remotely, then connect to Windows Management Instrumentation (WMI) services on the remote Windows host. From there you can submit a query that will inform you whenever a new event log entry is written.
Note that this does require that you have DCOM properly enabled and configured on the remote Windows host, and that appropriate exceptions have been set up in any firewalls. Details on this can be searched online, and are also referenced from the j-interop site, above.
The following example connects to a remote host using its NT domain, hostname, a username and a password, and sits in a loop, dumping every event log entry as they are logged by windows. The user must have been granted appropriate remote DCOM access permissions, but does not have to be an administrator.
import java.io.IOException;
import java.util.logging.Level;
import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.common.JISystem;
import org.jinterop.dcom.core.JIComServer;
import org.jinterop.dcom.core.JIProgId;
import org.jinterop.dcom.core.JISession;
import org.jinterop.dcom.core.JIString;
import org.jinterop.dcom.core.JIVariant;
import org.jinterop.dcom.impls.JIObjectFactory;
import org.jinterop.dcom.impls.automation.IJIDispatch;
public class EventLogListener
{
private static final String WMI_DEFAULT_NAMESPACE = "ROOT\\CIMV2";
private static JISession configAndConnectDCom( String domain, String user, String pass ) throws Exception
{
JISystem.getLogger().setLevel( Level.OFF );
try
{
JISystem.setInBuiltLogHandler( false );
}
catch ( IOException ignored )
{
;
}
JISystem.setAutoRegisteration( true );
JISession dcomSession = JISession.createSession( domain, user, pass );
dcomSession.useSessionSecurity( true );
return dcomSession;
}
private static IJIDispatch getWmiLocator( String host, JISession dcomSession ) throws Exception
{
JIComServer wbemLocatorComObj = new JIComServer( JIProgId.valueOf( "WbemScripting.SWbemLocator" ), host, dcomSession );
return (IJIDispatch) JIObjectFactory.narrowObject( wbemLocatorComObj.createInstance().queryInterface( IJIDispatch.IID ) );
}
private static IJIDispatch toIDispatch( JIVariant comObjectAsVariant ) throws JIException
{
return (IJIDispatch) JIObjectFactory.narrowObject( comObjectAsVariant.getObjectAsComObject() );
}
public static void main( String[] args )
{
if ( args.length != 4 )
{
System.out.println( "Usage: " + EventLogListener.class.getSimpleName() + " domain host username password" );
return;
}
String domain = args[ 0 ];
String host = args[ 1 ];
String user = args[ 2 ];
String pass = args[ 3 ];
JISession dcomSession = null;
try
{
// Connect to DCOM on the remote system, and create an instance of the WbemScripting.SWbemLocator object to talk to WMI.
dcomSession = configAndConnectDCom( domain, user, pass );
IJIDispatch wbemLocator = getWmiLocator( host, dcomSession );
// Invoke the "ConnectServer" method on the SWbemLocator object via it's IDispatch COM pointer. We will connect to
// the default ROOT\CIMV2 namespace. This will result in us having a reference to a "SWbemServices" object.
JIVariant results[] =
wbemLocator.callMethodA( "ConnectServer", new Object[] { new JIString( host ), new JIString( WMI_DEFAULT_NAMESPACE ),
JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), JIVariant.OPTIONAL_PARAM(), new Integer( 0 ),
JIVariant.OPTIONAL_PARAM() } );
IJIDispatch wbemServices = toIDispatch( results[ 0 ] );
// Now that we have a SWbemServices DCOM object reference, we prepare a WMI Query Language (WQL) request to be informed whenever a
// new instance of the "Win32_NTLogEvent" WMI class is created on the remote host. This is submitted to the remote host via the
// "ExecNotificationQuery" method on SWbemServices. This gives us all events as they come in. Refer to WQL documentation to
// learn how to restrict the query if you want a narrower focus.
final String QUERY_FOR_ALL_LOG_EVENTS = "SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA 'Win32_NTLogEvent'";
final int RETURN_IMMEDIATE = 16;
final int FORWARD_ONLY = 32;
JIVariant[] eventSourceSet =
wbemServices.callMethodA( "ExecNotificationQuery", new Object[] { new JIString( QUERY_FOR_ALL_LOG_EVENTS ), new JIString( "WQL" ),
new JIVariant( new Integer( RETURN_IMMEDIATE + FORWARD_ONLY ) ) } );
IJIDispatch wbemEventSource = (IJIDispatch) JIObjectFactory.narrowObject( ( eventSourceSet[ 0 ] ).getObjectAsComObject() );
// The result of the query is a SWbemEventSource object. This object exposes a method that we can call in a loop to retrieve the
// next Windows Event Log entry whenever it is created. This "NextEvent" operation will block until we are given an event.
// Note that you can specify timeouts, see the Microsoft documentation for more details.
while ( true )
{
// this blocks until an event log entry appears.
JIVariant eventAsVariant = (JIVariant) ( wbemEventSource.callMethodA( "NextEvent", new Object[] { JIVariant.OPTIONAL_PARAM() } ) )[ 0 ];
IJIDispatch wbemEvent = toIDispatch( eventAsVariant );
// WMI gives us events as SWbemObject instances (a base class of any WMI object). We know in our case we asked for a specific object
// type, so we will go ahead and invoke methods supported by that Win32_NTLogEvent class via the wbemEvent IDispatch pointer.
// In this case, we simply call the "GetObjectText_" method that returns us the entire object as a CIM formatted string. We could,
// however, ask the object for its property values via wbemEvent.get("PropertyName"). See the j-interop documentation and examples
// for how to query COM properties.
JIVariant objTextAsVariant = (JIVariant) ( wbemEvent.callMethodA( "GetObjectText_", new Object[] { new Integer( 1 ) } ) )[ 0 ];
String asText = objTextAsVariant.getObjectAsString().getString();
System.out.println( asText );
}
}
catch ( Exception e )
{
e.printStackTrace();
}
finally
{
if ( null != dcomSession )
{
try
{
JISession.destroySession( dcomSession );
}
catch ( Exception ex )
{
ex.printStackTrace();
}
}
}
}
}
~
On the Java side, you'll need a library that allows you to make native calls. Sun offers JNI, but it sounds like sort of a pain. Also consider:
https://github.com/twall/jna/
http://johannburkard.de/software/nativecall/
http://www.jinvoke.com/
On the Windows side, the function you're after is OpenEventLog. This should allow you to access a remote event log. See also Querying for Event Information.
If that doesn't sound right, I also found this for parsing the log files directly (not an approach I'd recommend but interesting nonetheless):
http://msdn.microsoft.com/en-us/library/bb309026.aspx
http://objectmix.com/java/75154-regarding-windows-event-log-file-parser-java.html
Read this article.
JNA 3.2.8 has both methods to read and write from the Windows event log.
You can see an example of write in log4jna.
Here's an example of read:
EventLogIterator iter = new EventLogIterator("Application");
while(iter.hasNext()) {
EventLogRecord record = iter.next();
System.out.println(record.getRecordNumber()
+ ": Event ID: " + record.getEventId()
+ ", Event Type: " + record.getType()
+ ", Event Source: " + record.getSource());
}
If you want true event log access from a remote machine, you will have to find a library which implements the EventLog Remoting Protocol Specification. Unfortunately, I have not yet found any such library in Java. However, much of the foundation for implementing this protocol has already been laid by the JCIFS and JARAPAC projects. The protocol itself (if I'm not mistaken) runs on top of the DCE/RPC protocol (implemented by JARAPAC) which itself runs on top of the SMB protocol (implemented by JCIFS).
I have already been using JCIFS and JARAPAC to implement some of EventLog's cousin protocols, such as remote registry access. I may be blind, but documentation seemed a little scarce regarding JARAPAC. If you are interested in implementing this, I can share with you what I have learned when I get some spare time!
Later!
there are a million (and one) options here ;)
you could look at sigar
http://cpansearch.perl.org/src/DOUGM/hyperic-sigar-1.6.3-src/docs/javadoc/org/hyperic/sigar/win32/EventLog.html
mind the licensing though....
or you could be quick and dirty and just periodically execute (and capture the output)
D:>cscript.exe c:\WINDOWS\system32\eventquery.vbs /v
then use event filtering params to refine the results etc...
http://technet.microsoft.com/en-us/library/cc772995(WS.10).aspx

Categories