How to get Windows process Description from Java? - java

Here is the code to get list of currently running process in windows.
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.win32.W32APIOptions;
import com.sun.jna.Native;
public class ListProcesses {
public static void main(String[] args) {
Kernel32 kernel32 = (Kernel32) Native.loadLibrary(Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference();
WinNT.HANDLE snapshot = kernel32.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new WinDef.DWORD(0));
try {
while (kernel32.Process32Next(snapshot, processEntry)) {
System.out.println(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile)+"\t"+processEntry.readField(""));
}
}
finally {
kernel32.CloseHandle(snapshot);
}
}
}
But I am unable to get description of the process/service in output.Kindly provide solution to get process description of each running proceess. Thanks in advance.

Instead of loading and invoking Kernel32 you could simply use the following code snippet in windows which uses the Runtime to execute a native process:
public List<String> execCommand(String ... command)
{
try
{
// execute the desired command
Process proc = null;
if (command.length > 1)
proc = Runtime.getRuntime().exec(command);
else
proc = Runtime.getRuntime().exec(command[0]);
// process the response
String line = "";
List<String> output = new ArrayList<>();
try (BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream())))
{
while ((line = input.readLine()) != null)
{
output.add(line);
}
}
return output;
}
catch (IOException e)
{
e.printStackTrace();
}
return Collections.<String>emptyList();
}
and then execute the command which invokes the Windows Management Information Command-line:
List<String> output = execCommand("wmic.exe PROCESS where name='"+processName+"'");
processName should contain the name of the running application or exe you try to get information from.
The returned list will then contain the line output of the status information of the running application. The first entry will contain header-information for the respective fields while the following entries will contain information on all matching process names.
Further infos on WMIC:
MSDN
Product documentation
Generating HTML output for WMI
HTH

As I stumbled today across this post here which showcases how to extract the version info from an executable file, your post came back to my mind and so I started a bit of investigation.
This further post states that the process description can only be extracted from the executable file itself so we need to lay our hands on JNA instead of parsing some output from WMIC or TASKLIST. This post further links the MSDN page for VerQueryValue function which provides a C way of extracting the process description. Here especially the 2nd parameter should be of interest as it defines what to return.
With the code mentioned in the first post it is now a bit of converting the C struct typedefs into Java equivalents. I will post the complete code here which at least works for me on Windows 7 64bit:
Maven pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>at.rovo.test</groupId>
<artifactId>JNI_Test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>JNI_Test</name>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- JNA 3.4
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>platform</artifactId>
<version>3.4.0</version>
</dependency>
-->
<!-- JNA 4.0.0 -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>4.0.0</version>
</dependency>
<!-- -->
</dependencies>
</project>
LangAndCodePage.java - a helper class which maps the extracted hex-values to human readable output of the language and code page information contained within the translation table. The values therefore are taken from this page here:
package at.rovo.test.jni_test;
import java.util.HashMap;
import java.util.Map;
public final class LangAndCodePage
{
private final static Map<String, String> languages = new HashMap<>();
private final static Map<String, String> codePage = new HashMap<>();
static
{
languages.put("0000", "Language Neutral");
languages.put("0401", "Arabic");
languages.put("0402", "Bulgarian");
languages.put("0403", "Catalan");
languages.put("0404", "Traditional Chinese");
languages.put("0405", "Czech");
languages.put("0406", "Danish");
languages.put("0407", "German");
languages.put("0408", "Greek");
languages.put("0409", "U.S. English");
languages.put("040A", "Castilian Spanish");
languages.put("040B", "Finnish");
languages.put("040C", "French");
languages.put("040D", "Hebrew");
languages.put("040E", "Hungarian");
languages.put("040F", "Icelandic");
languages.put("0410", "Italian");
languages.put("0411", "Japanese");
languages.put("0412", "Korean");
languages.put("0413", "Dutch");
languages.put("0414", "Norwegian ? Bokmal");
languages.put("0810", "Swiss Italian");
languages.put("0813", "Belgian Dutch");
languages.put("0814", "Norwegian ? Nynorsk");
languages.put("0415", "Polish");
languages.put("0416", "Portuguese (Brazil)");
languages.put("0417", "Rhaeto-Romanic");
languages.put("0418", "Romanian");
languages.put("0419", "Russian");
languages.put("041A", "Croato-Serbian (Latin)");
languages.put("041B", "Slovak");
languages.put("041C", "Albanian");
languages.put("041D", "Swedish");
languages.put("041E", "Thai");
languages.put("041F", "Turkish");
languages.put("0420", "Urdu");
languages.put("0421", "Bahasa");
languages.put("0804", "Simplified Chinese");
languages.put("0807", "Swiss German");
languages.put("0809", "U.K. English");
languages.put("080A", "Spanish (Mexico)");
languages.put("080C", "Belgian French");
languages.put("0C0C", "Canadian French");
languages.put("100C", "Swiss French");
languages.put("0816", "Portuguese (Portugal)");
languages.put("081A", "Serbo-Croatian (Cyrillic)");
codePage.put("0000", "7-bit ASCII");
codePage.put("03A4", "Japan (Shift ? JIS X-0208)");
codePage.put("03B5", "Korea (Shift ? KSC 5601)");
codePage.put("03B6", "Taiwan (Big5)");
codePage.put("04B0", "Unicode");
codePage.put("04E2", "Latin-2 (Eastern European)");
codePage.put("04E3", "Cyrillic");
codePage.put("04E4", "Multilingual");
codePage.put("04E5", "Greek");
codePage.put("04E6", "Turkish");
codePage.put("04E7", "Hebrew");
codePage.put("04E8", "Arabic");
}
// prohibit instantiation
private LangAndCodePage()
{
}
public static void printTranslationInfo(String lang, String cp)
{
StringBuilder builder = new StringBuilder();
builder.append("Language: ");
builder.append(languages.get(lang));
builder.append(" (");
builder.append(lang);
builder.append("); ");
builder.append("CodePage: ");
builder.append(codePage.get(cp));
builder.append(" (");
builder.append(cp);
builder.append(");");
System.out.println(builder.toString());
}
}
Last but not least the code which extracts the file version and the file description of the Windows explorer. The code contains plenty of documentation as I used it to learn the stuff myself ;)
package at.rovo.test.jni_test;
import java.io.IOException;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.VerRsrc.VS_FIXEDFILEINFO;
import com.sun.jna.platform.win32.Version;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class FileVersion
{
// The structure as implemented by the MSDN article
public static class LANGANDCODEPAGE extends Structure
{
/** The language contained in the translation table **/
public short wLanguage;
/** The code page contained in the translation table **/
public short wCodePage;
public LANGANDCODEPAGE(Pointer p)
{
useMemory(p);
}
public LANGANDCODEPAGE(Pointer p, int offset)
{
useMemory(p, offset);
}
public static int sizeOf()
{
return 4;
}
// newer versions of JNA require a field order to be set
#Override
protected List getFieldOrder()
{
List fieldOrder = new ArrayList();
fieldOrder.add("wLanguage");
fieldOrder.add("wCodePage");
return fieldOrder;
}
}
public static void main(String[] args) throws IOException
{
// http://msdn.microsoft.com/en-us/library/ms647464%28v=vs.85%29.aspx
//
// VerQueryValue will take two input and two output parameters
// 1. parameter: is a pointer to the version-information returned
// by GetFileVersionInfo
// 2. parameter: will take a string and return an output depending on
// the string:
// "\\"
// Is the root block and retrieves a VS_FIXEDFILEINFO struct
// "\\VarFileInfo\Translation"
// will return an array of Var variable information structure
// holding the language and code page identifier
// "\\StringFileInfo\\{lang-codepage}\\string-name"
// will return a string value of the language and code page
// requested. {lang-codepage} is a concatenation of a language
// and the codepage identifier pair found within the translation
// array in a hexadecimal string! string-name must be one of the
// following values:
// Comments, InternalName, ProductName, CompanyName,
// LegalCopyright, ProductVersion, FileDescription,
// LegalTrademarks, PrivateBuild, FileVersion,
// OriginalFilename, SpecialBuild
// 3. parameter: contains the address of a pointer to the requested
// version information in the buffer of the 1st parameter.
// 4. parameter: contains a pointer to the size of the requested data
// pointed to by the 3rd parameter. The length depends on
// the input of the 2nd parameter:
// *) For root block, the size in bytes of the structure
// *) For translation array values, the size in bytes of
// the array stored at lplpBuffer;
// *) For version information values, the length in
// character of the string stored at lplpBuffer;
String filePath = "C:\\Windows\\explorer.exe";
IntByReference dwDummy = new IntByReference();
dwDummy.setValue(0);
int versionlength =
Version.INSTANCE.GetFileVersionInfoSize(filePath, dwDummy);
if (versionlength > 0)
{
// will hold the bytes of the FileVersionInfo struct
byte[] bufferarray = new byte[versionlength];
// allocates space on the heap (== malloc in C/C++)
Pointer lpData = new Memory(bufferarray.length);
// will contain the address of a pointer to the requested version
// information
PointerByReference lplpBuffer = new PointerByReference();
// will contain a pointer to the size of the requested data pointed
// to by lplpBuffer.
IntByReference puLen = new IntByReference();
// reads versionLength bytes from the executable file into the FileVersionInfo struct buffer
boolean fileInfoResult =
Version.INSTANCE.GetFileVersionInfo(
filePath, 0, versionlength, lpData);
// retrieve file description for language and code page "i"
boolean verQueryVal =
Version.INSTANCE.VerQueryValue(
lpData, "\\", lplpBuffer, puLen);
// contains version information for a file. This information is
// language and code page independent
VS_FIXEDFILEINFO lplpBufStructure =
new VS_FIXEDFILEINFO(lplpBuffer.getValue());
lplpBufStructure.read();
int v1 = (lplpBufStructure.dwFileVersionMS).intValue() >> 16;
int v2 = (lplpBufStructure.dwFileVersionMS).intValue() & 0xffff;
int v3 = (lplpBufStructure.dwFileVersionLS).intValue() >> 16;
int v4 = (lplpBufStructure.dwFileVersionLS).intValue() & 0xffff;
System.out.println(
String.valueOf(v1) + "." +
String.valueOf(v2) + "." +
String.valueOf(v3) + "." +
String.valueOf(v4));
// creates a (reference) pointer
PointerByReference lpTranslate = new PointerByReference();
IntByReference cbTranslate = new IntByReference();
// Read the list of languages and code pages
verQueryVal = Version.INSTANCE.VerQueryValue(
lpData, "\\VarFileInfo\\Translation", lpTranslate, cbTranslate);
if (cbTranslate.getValue() > 0)
{
System.out.println("Found "+(cbTranslate.getValue()/4)
+ " translation(s) (length of cbTranslate: "
+ cbTranslate.getValue()+" bytes)");
}
else
{
System.err.println("No translation found!");
return;
}
// Read the file description
// msdn has this example here:
// for( i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ )
// where LANGANDCODEPAGE is a struct holding two WORDS. A word is
// 16 bits (2x 8 bit = 2 bytes) long and as the struct contains two
// words the length of the struct should be 4 bytes long
for (int i=0; i < (cbTranslate.getValue()/LANGANDCODEPAGE.sizeOf()); i++))
{
// writes formatted data to the specified string
// out: pszDest - destination buffer which receives the formatted, null-terminated string created from pszFormat
// in: ccDest - the size of the destination buffer, in characters. This value must be sufficiently large to accomodate the final formatted string plus 1 to account for the terminating null character.
// in: pszFormat - the format string. This string must be null-terminated
// in: ... The arguments to be inserted into the pszFormat string
// hr = StringCchPrintf(SubBlock, 50,
// TEXT("\\StringFileInfo\\%04x%04x\\FileDescription"),
// lpTranslate[i].wLanguage,
// lpTranslate[i].wCodePage);
// fill the structure with the appropriate values
LANGANDCODEPAGE langCodePage =
new LANGANDCODEPAGE(lpTranslate.getValue(), i*LANGANDCODEPAGE.sizeOf());
langCodePage.read();
// convert short values to hex-string:
// https://stackoverflow.com/questions/923863/converting-a-string-to-hexadecimal-in-java
String lang = String.format("%04x", langCodePage.wLanguage);
String codePage = String.format("%04x",langCodePage.wCodePage);
// see http://msdn.microsoft.com/en-us/library/windows/desktop/aa381058.aspx
// for proper values for lang and codePage
LangAndCodePage.printTranslationInfo(lang.toUpperCase(), codePage.toUpperCase());
// build the string for querying the file description stored in
// the executable file
StringBuilder subBlock = new StringBuilder();
subBlock.append("\\StringFileInfo\\");
subBlock.append(lang);
subBlock.append(codePage);
subBlock.append("\\FileDescription");
printDescription(lpData, subBlock.toString());
}
}
else
System.out.println("No version info available");
}
private static void printDescription(Pointer lpData, String subBlock)
{
PointerByReference lpBuffer = new PointerByReference();
IntByReference dwBytes = new IntByReference();
// Retrieve file description for language and code page "i"
boolean verQueryVal = Version.INSTANCE.VerQueryValue(
lpData, subBlock, lpBuffer, dwBytes);
// a single character is represented by 2 bytes!
// the last character is the terminating "\n"
byte[] description =
lpBuffer.getValue().getByteArray(0, (dwBytes.getValue()-1)*2);
System.out.println("File-Description: \""
+ new String(description, StandardCharsets.UTF_16LE)+"\"");
}
}
Finally, the output I'm receiving on my German Windows 7 64bit:
[exec:exec]
Version: 6.1.7601.17567
Found 1 translation(s) (length of cbTranslate: 4 bytes)
Language: German (0407); CodePage: Unicode (04B0);
File-Description: "Windows-Explorer"
HTH
#Edit: updated the code to use a class representation of the struct to simplify the extraction of the values (dealing with bytes does require them to swith the order of the bytes received - big and little endian issue)
Found after some tries an application that uses multiple languages and code pages within their file where I could test the output of multiple translations.
#Edit2: refactored the code and put it up on github. As mentioned in the comment, the output running the code from the github repo for the Logitech WingMan Event Monitor returns multiple language and codepage segments:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXX Information contained in: C:\Program Files\Logitech\Gaming Software\LWEMon.exe
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
File: C:\Program Files\Logitech\Gaming Software\LWEMon.exe
Version: 5.10.127.0
Language: U.S. English
CodePage: Multilingual
Original-Filename: LWEMon.exe
Company-Name: Logitech Inc.
File-Description: Logitech WingMan Event Monitor
File-Version: 5.10.127
Product-Version: 5.10.127
Product-Name: Logitech Gaming Software
Internal-Name: LWEMon
Private-Build:
Special-Build:
Legal-Copyright: © 1999-2010 Logitech. All rights reserved.
Legal-Trademark: Logitech, the Logitech logo, and other Logitech marks are owned by Logitech and may be registered. All other trademarks are the property of their respective owners.
Comment: Created by the WingMan Team.
File: C:\Program Files\Logitech\Gaming Software\LWEMon.exe
Version: 5.10.127.0
Language: Japanese
CodePage: Multilingual
Original-Filename: LWEMon.exe
Company-Name: Logicool Co. Ltd.
File-Description: Logicool WingMan Event Monitor
File-Version: 5.10.127
Product-Version: 5.10.127
Product-Name: Logicool Gaming Software
Internal-Name: LWEMon
Private-Build:
Special-Build:
Legal-Copyright: © 1999-2010 Logicool Co. Ltd. All rights reserved.
Legal-Trademark: Logicool, the Logicool logo, and other Logicool marks are owned by Logicool and may be registered. All other trademarks are the property of their respective owners.
Comment: Created by the WingMan Team.

(Answered by the OP in an answer-response. Converted to a community wiki answer. See Question with no answers, but issue solved in the comments (or extended in chat) )
Actually I find out another way ie. Windows PowerShell commands:
get-process notepad | select-object description.
Therefore, I am using command line to get descriptions of currently running process. Similarly for Services:
get-service | where {$_.status -eq 'running'}.

Related

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());

Finding if printer is online and ready to print

The following 4 questions didn't help, therefore this isn't a duplicate:
ONE, TWO, THREE, FOUR
I need to find a way to discover if the Printer that my system reports is available to print or not.
Printer page:
In the picture, the printer "THERMAL" is available to print, but "HPRT PPTII-A(USB)" isn't available to print. The System shows me that, by making the non-available printer shaded
Using the following code, I'm able to find all the printers in the system
public static List<String> getAvailablePrinters() {
DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, aset);
ArrayList<String> names = new ArrayList<String>();
for (PrintService p : services) {
Attribute at = p.getAttribute(PrinterIsAcceptingJobs.class);
if (at == PrinterIsAcceptingJobs.ACCEPTING_JOBS) {
names.add(p.getName());
}
}
return names;
}
output:
[HPRT PPTII-A(USB), THERMAL]
The problem is: This code shows all the printers that the system have ever installed.
What I need: This list should contain only the really available printers to print. In this example, it should only show "THERMAL", and not show "HPRT PPTII-A(USB)"
How can this be achieved?
If it is okay that the solution is Windows-specific, try WMI4Java. Here is my situation:
As you can see, my default printer "Kyocera Mita FS-1010" is inactive (greyed out) because I simply switched it off.
Now add this to your Maven POM:
<dependency>
<groupId>com.profesorfalken</groupId>
<artifactId>WMI4Java</artifactId>
<version>1.4.2</version>
</dependency>
Then it is as easy as this to list all printers with their respective status:
package de.scrum_master.app;
import com.profesorfalken.wmi4java.WMI4Java;
import com.profesorfalken.wmi4java.WMIClass;
import java.util.Arrays;
public class Printer {
public static void main(String[] args) {
System.out.println(
WMI4Java
.get()
.properties(Arrays.asList("Name", "WorkOffline"))
.getRawWMIObjectOutput(WMIClass.WIN32_PRINTER)
);
}
}
The console log looks as follows:
Name : WEB.DE Club SmartFax
WorkOffline : False
Name : Send To OneNote 2016
WorkOffline : False
Name : Microsoft XPS Document Writer
WorkOffline : False
Name : Microsoft Print to PDF
WorkOffline : False
Name : Kyocera Mita FS-1010 KX
WorkOffline : True
Name : FreePDF
WorkOffline : False
Name : FinePrint
WorkOffline : False
Name : Fax
WorkOffline : False
Please note that WorkOffline is True for the Kyocera printer. Probably this is what you wanted to find out.
And now a little modification in order to filter the printers list so as to only show active printers:
WMI4Java
.get()
.properties(Arrays.asList("Name", "WorkOffline"))
.filters(Arrays.asList("$_.WorkOffline -eq 0"))
.getRawWMIObjectOutput(WMIClass.WIN32_PRINTER)
Update: I was asked how to get a list of active printer names. Well, this is not so easy due to a shortcoming in WMI4Java for which I have just filed a pull request. It causes us to parse and filter the raw WMI output, but the code is still pretty straightforward:
package de.scrum_master.app;
import com.profesorfalken.wmi4java.WMI4Java;
import com.profesorfalken.wmi4java.WMIClass;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Printer {
public static void main(String[] args) {
String rawOutput = WMI4Java
.get()
.properties(Arrays.asList("Name", "WorkOffline"))
.filters(Arrays.asList("$_.WorkOffline -eq 0"))
.getRawWMIObjectOutput(WMIClass.WIN32_PRINTER);
List<String> printers = Arrays.stream(rawOutput.split("(\r?\n)"))
.filter(line -> line.startsWith("Name"))
.map(line -> line.replaceFirst(".* : ", ""))
.sorted()
.collect(Collectors.toList());
System.out.println(printers);
}
}
The console output looks like this:
[Fax, FinePrint, FreePDF, Microsoft Print to PDF, Microsoft XPS Document Writer, Send To OneNote 2016, WEB.DE Club SmartFax]
UPDATE:
Instead of querying WMI "win32_printer" object I would recommend using Powershell directly like this, its much cleaner API :
Get-Printer | where PrinterStatus -like 'Normal' | fl
To see all the printers and statuses:
Get-Printer | fl Name, PrinterStatus
To see all the attributes:
Get-Printer | fl
You can still use ProcessBuilder in Java as described below.
Before update:
Windows solution, query WMI "win32_printer" object:
public static void main(String[] args) {
// select printer that have state = 0 and status = 3, which indicates that printer can print
ProcessBuilder builder = new ProcessBuilder("powershell.exe", "get-wmiobject -class win32_printer | Select-Object Name, PrinterState, PrinterStatus | where {$_.PrinterState -eq 0 -And $_.PrinterStatus -eq 3}");
String fullStatus = null;
Process reg;
builder.redirectErrorStream(true);
try {
reg = builder.start();
fullStatus = getStringFromInputStream(reg.getInputStream());
reg.destroy();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.print(fullStatus);
}
For converting InputStream to String look here: comprehensive StackOverflow answer, or you can simply use:
public static String getStringFromInputStream(InputStream is) {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
try {
while ((length = is.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
} catch (IOException e1) {
e1.printStackTrace();
}
// StandardCharsets.UTF_8.name() > JDK 7
String finalResult = "";
try {
finalResult = result.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return finalResult;
}
Output:
Name PrinterState PrinterStatus
---- ------------ -------------
Foxit Reader PDF Printer 0 3
Send to OneNote 2010 0 3
Microsoft XPS Document Writer 0 3
Microsoft Print to PDF 0 3
Fax 0 3
\\192.168.50.192\POS_PRINTER 0 3
As you can see, you now have all the printers that are in working state in the string.
You can use your existing method (getAvailablePrinters()) and e.g. add something like this:
ArrayList<String> workingPrinter = new ArrayList<String>();
System.out.println("Working printers:");
for(String printer : getAvailablePrinters()){
if(fullStatus.contains("\n" + printer + " ")){ // add a newline character before the printer name and space after so that it catches exact name
workingPrinter.add(printer);
System.out.println(printer);
}
}
And now you will have a nice list of working printers.
Console output:
Working printers:
Send to OneNote 2010
Foxit Reader PDF Printer
Microsoft XPS Document Writer
Microsoft Print to PDF
Fax
\\192.168.50.192\POS_PRINTER
Of course you have to be careful with the names with this approach - e.g. if "POS_PRINTER" is in all printers but not in working printers list, it could still get added to the workingPrinters list, if there is a working printer named "POS_PRINTER 1" as that name contains "\nPOS_PRINTER " string...

get DFS/UNC info progromatically - Java

Ok I'll try and keep this short.
First let me explain exactly what I am trying to get. If you open Windows Explorer and go to a network drive there is a DFS tab there(must have DFS enabled VIA the servers on the network so it may not be there).
In that tab there is a list called the "Referral List"... I want what is in that box. I believe this is the DFS or UNC, you can correct me it will help me.
What I have is the \domainname.com\something$\BUS\blah\myDriveHome but this is tied to something else in that box that contains the actual server that that share is setting on and that share is what I need to run a compliance check.
I cannot use an exe that is not package with Windows 7 not any other exe as we cannot distribute exes.
So what have I done... a VERY thorough search for things like DFS/UNC paths from the command line, powershell, and registry and no go. Command line "net use" only return the linked path and not the server so that is useless.
I only ever post a question when I hit a wall that is taking up to much programming time.
If anyone has an info it would be grateful.
Thanks
I was able to steal the C# code in this answer here and make some modifications so it works with .Net 2.0, and use it within PowerShell:
$dfsCode = #'
using System;
using System.Runtime.InteropServices;
public static class Dfs
{
private enum NetDfsInfoLevel
{
DfsInfo1 = 1,
DfsInfo2 = 2,
DfsInfo3 = 3,
DfsInfo4 = 4,
DfsInfo5 = 5,
DfsInfo6 = 6,
DfsInfo7 = 7,
DfsInfo8 = 8,
DfsInfo9 = 9,
DfsInfo50 = 50,
DfsInfo100 = 100,
DfsInfo150 = 150,
}
[DllImport("netapi32.dll", SetLastError = true)]
private static extern int NetApiBufferFree(IntPtr buffer);
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int NetDfsGetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string DfsEntryPath, // DFS entry path for the volume
[MarshalAs(UnmanagedType.LPWStr)] string ServerName, // This parameter is currently ignored and should be NULL
[MarshalAs(UnmanagedType.LPWStr)] string ShareName, // This parameter is currently ignored and should be NULL.
NetDfsInfoLevel Level, // Level of information requested
out IntPtr Buffer // API allocates and returns buffer with requested info
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct DFS_INFO_3
{
[MarshalAs(UnmanagedType.LPWStr)]
public string EntryPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string Comment;
public int State;
public int NumberOfStorages;
public IntPtr Storage;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct DFS_STORAGE_INFO
{
public int State;
[MarshalAs(UnmanagedType.LPWStr)]
public string ServerName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ShareName;
}
private static T GetStruct<T>(IntPtr buffer, int offset)where T:struct
{
T r = new T();
r = (T) Marshal.PtrToStructure((IntPtr)((long)buffer + offset * Marshal.SizeOf(r)), typeof(T));
return r;
}
public static string GetDfsInfo(string server)
{
string rval = null;
IntPtr b;
int r = NetDfsGetInfo(server, null, null, NetDfsInfoLevel.DfsInfo3, out b);
if(r != 0)
{
NetApiBufferFree(b);
// return passed string if not DFS
return rval;
}
DFS_INFO_3 sRes = GetStruct<DFS_INFO_3>(b,0);
if(sRes.NumberOfStorages > 0)
{
DFS_STORAGE_INFO sResInfo = GetStruct<DFS_STORAGE_INFO>(sRes.Storage,0);
rval = string.Concat(#"\\", sResInfo.ServerName, #"\", sResInfo.ShareName, #"\");
}
NetApiBufferFree(b);
return rval;
}
}
'#
Add-Type -TypeDefinition $dfsCode
[Dfs]::GetDfsInfo('\\ad.domain.com\Share')
This code will work with PowerShell 2.0 which is included with Windows 7.
I went another direction with the use of PSEXEC and DFSUtil to find the DFS info VIA the remote PC. Returns a lot of info but I filtered it in PowerShell after reading the file and matching the UNC. I would post the how to but I had to do some major adapting on my end with the info that is on a few other sites for DFSUtil and what to look for and PSExec. I will note this for PSEXEC:
cmd.exe /s /c C:\Temp\psexec.exe 2> $null
That "2> $null" will save you some headaches and your script crashing if the return is in the error channel. You will need to run it in the PS console though without that to catch the error, but when you have a script like mine performing 50+ system checks you don't want the whole thing to halt for just one error.

Get the whole index of Maven Central [duplicate]

I have downloaded the indexes generated for Maven Central from http://mirrors.ibiblio.org/pub/mirrors/maven2/dot-index/nexus-maven-repository-index.gz
I would like to list the artifacts information from these index files (groupId, artifactId, version for example). I have read that there is a high level API for that. It seems that I have to use the following maven dependency. However, I don't know what is the entry point to use (which class?) and how to use it to access those files:
<dependency>
<groupId>org.sonatype.nexus</groupId>
<artifactId>nexus-indexer</artifactId>
<version>3.0.4</version>
</dependency>
Take a peek at https://github.com/cstamas/maven-indexer-examples project.
In short: you dont need to download the GZ/ZIP (new/legacy format) manually, it will indexer take care of doing it for you (moreover, it will handle incremental updates for you too, if possible).
GZ is the "new" format, independent of Lucene index-format (hence, independent of Lucene version) containing data only, while the ZIP is "old" format, which is actually plain Lucene 2.4.x index zipped up. No data content change happens currently, but is planned in future.
As I said, there is no data content difference between two, but some fields (like you noticed) are Indexed but not stored on index, hence, if you consume the ZIP format, you will have them searchable, but not retrievable.
The https://github.com/cstamas/maven-indexer-examples is obsolete. And the build fails (tests do not pass).
The Nexus Indexer has moved along and included the examples too:
https://github.com/apache/maven-indexer/tree/master/indexer-examples
That builds, and the code works.
Here is a simplified version if you want to roll your own:
Maven:
<dependencies>
<dependency>
<groupId>org.apache.maven.indexer</groupId>
<artifactId>indexer-core</artifactId>
<version>6.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!-- For ResourceFetcher implementation, if used -->
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-http-lightweight</artifactId>
<version>2.3</version>
<scope>compile</scope>
</dependency>
<!-- Runtime: DI, but using Plexus Shim as we use Wagon -->
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.plexus</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.sonatype.sisu</groupId>
<artifactId>sisu-guice</artifactId>
<version>3.2.4</version>
</dependency>
Java:
public IndexToGavMappingConverter(File dataDir, String id, String url)
throws PlexusContainerException, ComponentLookupException, IOException
{
this.dataDir = dataDir;
// Create Plexus container, the Maven default IoC container.
final DefaultContainerConfiguration config = new DefaultContainerConfiguration();
config.setClassPathScanning( PlexusConstants.SCANNING_INDEX );
this.plexusContainer = new DefaultPlexusContainer(config);
// Lookup the indexer components from plexus.
this.indexer = plexusContainer.lookup( Indexer.class );
this.indexUpdater = plexusContainer.lookup( IndexUpdater.class );
// Lookup wagon used to remotely fetch index.
this.httpWagon = plexusContainer.lookup( Wagon.class, "http" );
// Files where local cache is (if any) and Lucene Index should be located
this.centralLocalCache = new File( this.dataDir, id + "-cache" );
this.centralIndexDir = new File( this.dataDir, id + "-index" );
// Creators we want to use (search for fields it defines).
// See https://maven.apache.org/maven-indexer/indexer-core/apidocs/index.html?constant-values.html
List<IndexCreator> indexers = new ArrayList();
// https://maven.apache.org/maven-indexer/apidocs/org/apache/maven/index/creator/MinimalArtifactInfoIndexCreator.html
indexers.add( plexusContainer.lookup( IndexCreator.class, "min" ) );
// https://maven.apache.org/maven-indexer/apidocs/org/apache/maven/index/creator/JarFileContentsIndexCreator.html
//indexers.add( plexusContainer.lookup( IndexCreator.class, "jarContent" ) );
// https://maven.apache.org/maven-indexer/apidocs/org/apache/maven/index/creator/MavenPluginArtifactInfoIndexCreator.html
//indexers.add( plexusContainer.lookup( IndexCreator.class, "maven-plugin" ) );
// Create context for central repository index.
this.centralContext = this.indexer.createIndexingContext(
id + "Context", id, this.centralLocalCache, this.centralIndexDir,
url, null, true, true, indexers );
}
final IndexSearcher searcher = this.centralContext.acquireIndexSearcher();
try
{
final IndexReader ir = searcher.getIndexReader();
Bits liveDocs = MultiFields.getLiveDocs(ir);
for ( int i = 0; i < ir.maxDoc(); i++ )
{
if ( liveDocs == null || liveDocs.get( i ) )
{
final Document doc = ir.document( i );
final ArtifactInfo ai = IndexUtils.constructArtifactInfo( doc, this.centralContext );
if (ai == null)
continue;
if (ai.getSha1() == null)
continue;
if (ai.getSha1().length() != 40)
continue;
if ("javadoc".equals(ai.getClassifier()))
continue;
if ("sources".equals(ai.getClassifier()))
continue;
out.append(StringUtils.lowerCase(ai.getSha1())).append(' ');
out.append(ai.getGroupId()).append(":");
out.append(ai.getArtifactId()).append(":");
out.append(ai.getVersion()).append(":");
out.append(StringUtils.defaultString(ai.getClassifier()));
out.append('\n');
}
}
}
finally
{
this.centralContext.releaseIndexSearcher( searcher );
}
We use this in the Windup project - JBoss migration tool.
The legacy zip index is a simple lucene index. I was able to open it with Luke
and write some simple lucene code to dump out the headers of interest ("u" in this case)
import org.apache.lucene.document.Document;
import org.apache.lucene.search.IndexSearcher;
public class Dumper {
public static void main(String[] args) throws Exception {
IndexSearcher searcher = new IndexSearcher("c:/PROJECTS/Test/index");
for (int i = 0; i < searcher.maxDoc(); i++) {
Document doc = searcher.doc(i);
String metadata = doc.get("u");
if (metadata != null) {
System.out.println(metadata);
}
}
}
}
Sample output ...
org.ioke|ioke-lang-lib|P-0.4.0-p11|NA
org.jboss.weld.archetypes|jboss-javaee6-webapp|1.0.1.CR2|sources|jar
org.jboss.weld.archetypes|jboss-javaee6-webapp|1.0.1.CR2|NA
org.nutz|nutz|1.b.37|javadoc|jar
org.nutz|nutz|1.b.37|sources|jar
org.nutz|nutz|1.b.37|NA
org.openengsb.wrapped|com.google.gdata|1.41.5.w1|NA
org.openengsb.wrapped|openengsb-wrapped-parent|6|NA
There may be better ways to achieve this though ...
For the records, there is now a tool to extract and export maven indexes as text files: the Maven index exporter. It's available as a Docker image and no code is required.
It basically downloads all .gz index files, extracts the indexes using maven-indexer cli and exports them to a text file with clue. It has been tested on Maven Central and works on many other Maven repositories.

Categories