Is it possible to get the process name of a Process object? - java

I have several process objects from which I'd like to get their names. Something like Thread-34 or Thread-74, etc.
I know I can build such with the pid, but is there something built in?
I know how to get their pid or info, but that doesn't help me to get their names.
ProcessBuilder pb = new ProcessBuilder(command);
p = pb.start();
p.pid()
p.info()
Is it possible (Java 15)?

Use p.info().command(). It returns the executable pathname of the process (reference). Note that it returns an Optional object: you need to check if it has a value before getting the pathname string out of it:
var pathname = p.info().command();
if (pathname.isPresent()) {
System.out.println(pathname.get());
}
If you would like to refer to your processes by custom names (like "Process-1", "Process-2", ...) then you can use a HashMap:
import java.util.HashMap;
public class App {
public static void main(String[] args) throws Exception {
// Create processes with names
var processes = new HashMap<String, Process>();
for (var i = 0; i < 5; ++i) {
var processBuilder = new ProcessBuilder("cmd");
var process = processBuilder.start();
var processName = "Process-" + (i + 1); // Name can be anything you want
processes.put(processName, process);
}
// List process names
for (var processName : processes.keySet()) {
System.out.println(processName);
}
// Refer to a process by name
System.out.println(processes.get("Process-3").pid());
}
}
Example output:
Process-1
Process-3
Process-2
Process-5
Process-4
12780

Related

Java - how to call Java main() from a new process thread

I am trying to build out Integration Tests (IT) for an application. The application has at its centre a Server, written in Java, that set-ups a message queue from which it polls for messages sent to it on a particular port-number. I would like to write an Integration Test which fires some messages at this server/port-number and tests the response.
Below is the full list of VM arguments that I run when I start the server from within Intellij manually. I can start the server this way and then fire my test messages at it but I would like to convert this into IT tests so that I can start/stop the server programmatically at the start and end of my tests.
The problem I am having is that I dont know how to start the server application from within my test class. So to ask it more plainly, how to start the Java main() of a class in its own process thread. I am working within Intellij (2019.1) and Java 8. Should I be using the ProcessBuilder or ExecutorService maybe ?
I think I can use System.setProperty for some of the VM arguments but not sure how to specify the -XX ones...so that would be a second part to this question.
-Djava.endorsed.dirs=/Users/xxx/dev/src/repo/xxx/myapp/target/classes/lib/endorsed
-Dmyapp.home=/private/var/tmp/myapp
-Dmyapp.log.dir=/private/var/tmp
-Dmyapp.env=/Users/xxx/dev/src/repo/xxx/myapp/target/classes/etc/examples/environment-apa.sh
-Dsimplelogger.properties=/private/var/tmp/myapp/etc/simplelogger.properties
-server
-XX:CompileThreshold=2500
-XX:+UseFastAccessorMethods
-Xss256k
-Xmx1g
-Xms512m
I've tried implementing this using the ExecutorService
public class ServerTest {
#Test
public void shouldStartServerOk() {
try{
startServer();
}catch(Exception e){
e.printStackTrace();
fail();
}
}
private void startServer(){
ExecutorService executor = Executors.newFixedThreadPool(1);
Runnable runnableTask = new Runnable() {
#Override
public void run() {
String [] args = new String[0];
try {
System.setProperty("java.endorsed.dirs", "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed");
System.setProperty("myapp.home", "/private/var/tmp/myapp");
System.setProperty("myapp.log.dir", "/private/var/tmp");
System.setProperty("myapp.env", "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh");
System.setProperty("simplelogger.properties", "/private/var/tmp/myapp/etc/simplelogger.properties");
System.setProperty("-server", "TRUE");
MyApp.main(args);
} catch (Exception e) {
e.printStackTrace();
}
}
};
executor.execute(runnableTask);
// shut down the executor manually
//executor.shutdown();
}
But this doesn't seem to work although the test does complete green. When I debug the process, the flow doesn't Step-Into MyApp.main(args). Strangely when I just try running MyApp.main(args) on its own outside of the ExecutorService then it starts and runs fine until I hit Stop in my IDE. This is behaviour I would like just the additional ability to Start/Stop the process.
UPDATE-1:
following the comments from #dmitrievanthony and #RealSkeptic I have tried to implement something along those lines based on SO question, Executing a Java application in a separate process/636367,
public final class JavaProcess {
private JavaProcess() {}
public static int exec(Class klass) throws IOException,
InterruptedException {
String javaHome = System.getProperty("java.home");
String javaBin = javaHome +
File.separator + "bin" +
File.separator + "java";
String classpath = System.getProperty("java.class.path");
String className = klass.getName();
ProcessBuilder processBuilder = new ProcessBuilder(
javaBin,
"-cp",
classpath,
className
);
Map<String, String> env = processBuilder.environment();
env.put("java.endorsed.dirs", "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed");
env.put("myapp.home", "/private/var/tmp/myapp");
env.put("myapp.log.dir", "/private/var/tmp");
env.put("myapp.env", "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh");
env.put("simplelogger.properties", "/private/var/tmp/myapp/etc/simplelogger.properties");
env.put("-XX:CompileThreshold", "2500");
env.put("-XX:+UseFastAccessorMethods", "");
env.put("-Xss256k", "");
env.put("-Xmx1g", "");
env.put("-Xms512m", "");
Process process = processBuilder.inheritIO().start();
process.waitFor();
return process.exitValue();
}
and calling it in my myAppIT test class as int status = JavaProcess.exec(MyAapp.class);
I can now see my class "MyApp" starting - and can confirm that the process flow is running into my MyApp.main() class. The problem now is that the System.env variables that I am setting in my ProcessBuilder do not appear to be available in the called programme ie. when I print to log System.getProperty("myapp.home") its returning null even though I can confirm that it is being set as shown in the code - does anyone have any ideas on this one please ?
UPDATE-2: I am trying to implement suggestion by #RealSkeptic and passing in the arguments in a similar way as passing commandline arguments as shown in the code snippet below. Now I am getting an exception
Error: Could not find or load main class xxx.xxx.xxx.xxx.MyApp -Djava.endorsed.dirs=.Users.xxx.dev.src.gitlab.myapp.myapp.target.classes.lib.endorsed
one problem I see is that the forward slashes of the path have been translated to ".". The path should read, Djava.endorsed.dirs=/Users/xxx/dev/src/gitlab/myapp/myapp/target/classes/lib/endorsed
ProcessBuilder processBuilder = new ProcessBuilder(
javaBin,
"-cp",
classpath,
className + " " +
"-Djava.endorsed.dirs=" + "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed " +
"-Dmyapp.home=/private/var/tmp/myapp " +
"-Dmyapp.log.dir=/private/var/tmp" +
"-Dmyapp.env=/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh " +
"-Dsimplelogger.properties=/private/var/tmp/myapp/etc/simplelogger.properties " +
"-server " +
"-XX:CompileThreshold=2500 " +
"-XX:+UseFastAccessorMethods " +
"-Xss256k " +
"-Xmx1g " +
"-Xms512m"
);
Update-3 following the last comment from #RealSkeptic I've modified my code (see below) and this now works.
ProcessBuilder processBuilder = new ProcessBuilder(
javaBin,
"-cp",
classpath,
"-Djava.endorsed.dirs=" + "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed",
"-Dmyapp.home=/private/var/tmp/myapp",
"-Dmyapp.log.dir=/private/var/tmp",
"-Dmyapp.env=/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh",
"-Dsimplelogger.properties=/private/var/tmp/myapp/etc/simplelogger.properties ",
"-server",
"-XX:CompileThreshold=2500",
"-XX:+UseFastAccessorMethods",
"-Xss256k",
"-Xmx1g",
"-Xms512m",
className
);
The below is copied from UPDATE-3 which I am posting as the answer. Thank you to those who responded and especially #RealSkeptic.
ProcessBuilder processBuilder = new ProcessBuilder(
javaBin,
"-cp",
classpath,
"-Djava.endorsed.dirs=" + "/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/lib/endorsed",
"-Drrc.home=/private/var/tmp/myapp",
"-Drrc.log.dir=/private/var/tmp",
"-Drrc.env=/Users/xxx/dev/src/gitlab/xxx/myapp/target/classes/etc/examples/environment-apa.sh",
"-Dsimplelogger.properties=/private/var/tmp/myapp/etc/simplelogger.properties ",
"-server",
"-XX:CompileThreshold=2500",
"-XX:+UseFastAccessorMethods",
"-Xss256k",
"-Xmx1g",
"-Xms512m",
className
);
I have refactored the above to put each of the arguments into a List so the call to ProcessBuilder reduces to,
ProcessBuilder processBuilder = new ProcessBuilder(arguments);
Process process = processBuilder.inheritIO().start();
To Stop the process you just need to call
process.destroy();

Implementing language locales into array to be used in a loop

I'm trying to read every file in a directory, clean up with java util.locale, then write to a new directory. The reading and writing methods work, the Locale.SPANISH might be the issue as I have read in other posts.
I iterated through the available languages in the java.util.locale, spanish was in there.
First, the array issue: the following extract of code below is the long way of entering the Locale.(LANGUAGE) into the array. This seems to work fine. However, I can't understand why the 'short' way doesn't seem to work.
String[] languageLocale = new String[fileArray.length];
languageLocale[0] = "Locale.ENGLISH";
languageLocale[1] = "Locale.FRENCH";
languageLocale[2] = "Locale.GERMAN";
languageLocale[3] = "Locale.ITALIAN";
languageLocale[4] = "Locale.SPANISH";
The short way:
String[] languageLocale = new String[("Locale.ENGLISH" , "Locale.FRENCH" , "Locale.GERMAN" , "Locale.ITALIAN" , "Locale.SPANISH")];
I need to input the Locale.(langauge) into a string so they can be called in the following:
File file = new File("\\LanguageGuessing5.0\\Learning\\");
File[] fileArray = file.listFiles();
ArrayList<String> words = new ArrayList<String>();
for (int i = 0; i < fileArray.length; i++) {
if (fileArray[i].isFile()) {
if (fileArray[i].isHidden()) {
continue;
} else {
String content = readUTF8File("\\LanguageGuessing5.0\\Learning\\"+fileArray[i].getName());
words = extractWords(content, languageLocale[i]);
outputWordsToUTF8File("\\LanguageGuessing5.0\\Model\\"+ fileArray[i].getName() + "out.txt", words);
}
} else if (fileArray[i].isDirectory()) {
System.out.println("Directory " + fileArray[i].getName());
}
}
The following method call:
words = extractWords(content, languageLocale[i]);
also presents the following error:
The method extractWords(String, Locale) in the type CleaningText(the class name) is not applicable for the arguments (String, String)
My understanding is that while the array argument is not a locale, the string holds the correct text to make it valid. I'm clearly incorrect, I'm hoping someone could explain how this works.
The input types of the methods are below for context:
public static String readUTF8File(String filePath)
public static ArrayList extractWords(String inputText, Locale currentLocale)
public static void outputWordsToUTF8File(String filePath, ArrayList wordList)
Many thanks in advance

Java: Marshalling using JaxB to XML, how to properly multithread

I am trying to take a very long file of strings and convert it to an XML according to a schema I was given. I used jaxB to create classes from that schema. Since the file is very large I created a thread pool to improve the performance but since then it only processes one line of the file and marshalls it to the XML file, per thread.
Below is my home class where I read from the file. Each line is a record of a transaction, for every new user encountered a list is made to store all of that users transactions and each list is put into a HashMap. I made it a ConcurrentHashMap because multiple threads will work on the map simultaneously, is this the correct thing to do?
After the lists are created a thread is made for each user. Each thread runs the method ProcessCommands below and receives from home the list of transactions for its user.
public class home{
public static File XMLFile = new File("LogFile.xml");
Map<String,List<String>> UserMap= new ConcurrentHashMap<String,List<String>>();
String[] UserNames = new String[5000];
int numberOfUsers = 0;
try{
BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
String line;
while ((line = reader.readLine()) != null)
{
parsed = line.split(",|\\s+");
if(!parsed[2].equals("./testLOG")){
if(Utilities.checkUserExists(parsed[2], UserNames) == false){ //User does not already exist
System.out.println("New User: " + parsed[2]);
UserMap.put(parsed[2],new ArrayList<String>()); //Create list of transactions for new user
UserMap.get(parsed[2]).add(line); //Add First Item to new list
UserNames[numberOfUsers] = parsed[2]; //Add new user
numberOfUsers++;
}
else{ //User Already Existed
UserMap.get(parsed[2]).add(line);
}
}
}
reader.close();
} catch (IOException x) {
System.err.println(x);
}
//get start time
long startTime = new Date().getTime();
tCount = numberOfUsers;
ExecutorService threadPool = Executors.newFixedThreadPool(tCount);
for(int i = 0; i < numberOfUsers; i++){
System.out.println("Starting Thread " + i + " for user " + UserNames[i]);
Runnable worker = new ProcessCommands(UserMap.get(UserNames[i]),UserNames[i], XMLfile);
threadPool.execute(worker);
}
threadPool.shutdown();
while(!threadPool.isTerminated()){
}
System.out.println("Finished all threads");
}
Here is the ProcessCommands class. The thread receives the list for its user and creates a marshaller. From what I unserstand marshalling is not thread safe so it is best to create one for each thread, is this the best way to do that?
When I create the marshallers I know that each from (from each thread) will want to access the created file causing conflicts, I used synchronized, is that correct?
As the thread iterates through it's list, each line calls for a certain case. There are a lot so I just made pseudo-cases for clarity. Each case calls the function below.
public class ProcessCommands implements Runnable{
private static final boolean DEBUG = false;
private List<String> list = null;
private String threadName;
private File XMLfile = null;
public Thread myThread;
public ProcessCommands(List<String> list, String threadName, File XMLfile){
this.list = list;
this.threadName = threadName;
this.XMLfile = XMLfile;
}
public void run(){
Date start = null;
int transactionNumber = 0;
String[] parsed = new String[8];
String[] quoteParsed = null;
String[] universalFormatCommand = new String[9];
String userCommand = null;
Connection connection = null;
Statement stmt = null;
Map<String, UserObject> usersMap = null;
Map<String, Stack<BLO>> buyMap = null;
Map<String, Stack<SLO>> sellMap = null;
Map<String, QLO> stockCodeMap = null;
Map<String, BTO> buyTriggerMap = null;
Map<String, STO> sellTriggerMap = null;
Map<String, USO> usersStocksMap = null;
String SQL = null;
int amountToAdd = 0;
int tempDollars = 0;
UserObject tempUO = null;
BLO tempBLO = null;
SLO tempSLO = null;
Stack<BLO> tempStBLO = null;
Stack<SLO> tempStSLO = null;
BTO tempBTO = null;
STO tempSTO = null;
USO tempUSO = null;
QLO tempQLO = null;
String stockCode = null;
String quoteResponse = null;
int usersDollars = 0;
int dollarAmountToBuy = 0;
int dollarAmountToSell = 0;
int numberOfSharesToBuy = 0;
int numberOfSharesToSell = 0;
int quoteStockInDollars = 0;
int shares = 0;
Iterator<String> itr = null;
int transactionCount = list.size();
System.out.println("Starting "+threadName+" - listSize = "+transactionCount);
//UO dollars, reserved
usersMap = new HashMap<String, UserObject>(3); //userName -> UO
//USO shares
usersStocksMap = new HashMap<String, USO>(); //userName+stockCode -> shares
//BLO code, timestamp, dollarAmountToBuy, stockPriceInDollars
buyMap = new HashMap<String, Stack<BLO>>(); //userName -> Stack<BLO>
//SLO code, timestamp, dollarAmountToSell, stockPriceInDollars
sellMap = new HashMap<String, Stack<SLO>>(); //userName -> Stack<SLO>
//BTO code, timestamp, dollarAmountToBuy, stockPriceInDollars
buyTriggerMap = new ConcurrentHashMap<String, BTO>(); //userName+stockCode -> BTO
//STO code, timestamp, dollarAmountToBuy, stockPriceInDollars
sellTriggerMap = new HashMap<String, STO>(); //userName+stockCode -> STO
//QLO timestamp, stockPriceInDollars
stockCodeMap = new HashMap<String, QLO>(); //stockCode -> QLO
//create user object and initialize stacks
usersMap.put(threadName, new UserObject(0, 0));
buyMap.put(threadName, new Stack<BLO>());
sellMap.put(threadName, new Stack<SLO>());
try {
//Marshaller marshaller = getMarshaller();
synchronized (this){
Marshaller marshaller = init.jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.marshal(LogServer.Root,XMLfile);
marshaller.marshal(LogServer.Root,System.out);
}
} catch (JAXBException M) {
M.printStackTrace();
}
Date timing = new Date();
//universalFormatCommand = new String[8];
parsed = new String[8];
//iterate through workload file
itr = this.list.iterator();
while(itr.hasNext()){
userCommand = (String) itr.next();
itr.remove();
parsed = userCommand.split(",|\\s+");
transactionNumber = Integer.parseInt(parsed[0].replaceAll("\\[", "").replaceAll("\\]", ""));
universalFormatCommand = Utilities.FormatCommand(parsed, parsed[0]);
if(transactionNumber % 100 == 0){
System.out.println(this.threadName + " - " +transactionNumber+ " - "+(new Date().getTime() - timing.getTime())/1000);
}
/*System.out.print("UserCommand " +transactionNumber + ": ");
for(int i = 0;i<8;i++)System.out.print(universalFormatCommand[i]+ " ");
System.out.print("\n");*/
//switch for user command
switch (parsed[1].toLowerCase()) {
case "One"
*Do Stuff"
LogServer.create_Log(universalFormatCommand, transactionNumber, CommandType.ADD);
break;
case "Two"
*Do Stuff"
LogServer.create_Log(universalFormatCommand, transactionNumber, CommandType.ADD);
break;
}
}
}
The function create_Log has multiple cases so as before, for clarity I just left one. The case "QUOTE" only calls one object creation function but other other cases can create multiple objects. The type 'log' is a complex XML type that defines all the other object types so in each call to create_Log I create a log type called Root. The class 'log' generated by JaxB included a function to create a list of objects. The statement:
Root.getUserCommandOrQuoteServerOrAccountTransaction().add(quote_QuoteType);
takes the root element I created, creates a list and adds the newly created object 'quote_QuoteType' to that list. Before I added threading this method successfully created a list of as many objects as I wanted then marshalled them. So I'm pretty positive the bit in class 'LogServer' is not the issue. It is something to do with the marshalling and syncronization in the ProcessCommands class above.
public class LogServer{
public static log Root = new log();
public static QuoteServerType Log_Quote(String[] input, int TransactionNumber){
ObjectFactory factory = new ObjectFactory();
QuoteServerType quoteCall = factory.createQuoteServerType();
**Populate the QuoteServerType object called quoteCall**
return quoteCall;
}
public static void create_Log(String[] input, int TransactionNumber, CommandType Command){
System.out.print("TRANSACTION "+TransactionNumber + " is " + Command + ": ");
for(int i = 0; i<input.length;i++) System.out.print(input[i] + " ");
System.out.print("\n");
switch(input[1]){
case "QUOTE":
System.out.print("QUOTE CASE");
QuoteServerType quote_QuoteType = Log_Quote(input,TransactionNumber);
Root.getUserCommandOrQuoteServerOrAccountTransaction().add(quote_QuoteType);
break;
}
}
So you wrote a lot of code, but have you try if it is actually working? After quick look I doubt it. You should test your code logic part by part not going all the way till the end. It seems you are just staring with Java. I would recommend practice first on simple one threaded applications. Sorry if I sound harsh, but I will try to be constructive as well:
Per convention, the classes names are starts with capital letter, variables by small, you do it other way.
You should make a method in you home (Home) class not a put all your code in the static block.
You are reading the whole file to the memory, you do not process it line by line. After the Home is initialized literary whole content of file will be under UserMap variable. If the file is really large you will run out of the heap memory. If you assume large file than you cannot do it and you have to redisign your app to store somewhere partial results. If your file is smaller than memmory you could keep it like that (but you said it is large).
No need for UserNames, the UserMap.containsKey will do the job
Your thread pools size should be in the range of your cores not number of users as you will get thread trashing (if you have blocking operation in your code make tCount = 2*processors if not keep it as number of processors). Once one ProcessCommand finish, the executor will start another one till you finish all and you will be efficiently using all your processor cores.
DO NOT while(!threadPool.isTerminated()), this line will completely consume one processor as it will be constantly checking, call awaitTermination instead
Your ProcessCommand, has view map variables which will only had one entry cause as you said, each will process data from one user.
The synchronized(this) is Process will not work, as each thread will synchronized on different object (different isntance of process).
I believe creating marshaller is thread safe (check it) so no need to synchronization at all
You save your log (whatever it is) before you did actual processing in of the transactions lists
The marshalling will override content of the file with current state of LogServer.Root. If it is shared bettween your proccsCommand (seems so) what is the point in saving it in each thread. Do it once you are finished.
You dont need itr.remove();
The log class (for the ROOT variable !!!) needs to be thread-safe as all the threads will call the operations on it (so the list inside the log class must be concurrent list etc).
And so on.....
I would recommend, to
Start with simple one thread version that actually works.
Deal with processing line by line, (store reasults for each users in differnt file, you can have cache with transactions for recently used users so not to keep writing all the time to the disk (see guava cache)
Process multithreaded each user transaction to your user log objects (again if it is a lot you have to save them to the disk not keep all in memmory).
Write code that combines logs from diiffernt users to create one (again you may want to do it mutithreaded), though it will be mostly IO operations so not much gain and more tricky to do.
Good luck
override cont

How to read Nutch content from Java/Scala?

I'm using Nutch to crawl some websites (as a process that runs separate of everything else), while I want to use a Java (Scala) program to analyse the HTML data of websites using Jsoup.
I got Nutch to work by following the tutorial (without the script, only executing the individual instructions worked), and I think it's saving the websites' HTML in the crawl/segments/<time>/content/part-00000 directory.
The problem is that I cannot figure out how to actually read the website data (URLs and HTML) in a Java/Scala program. I read this document, but find it a bit overwhelming since I've never used Hadoop.
I tried to adapt the example code to my environment, and this is what I arrived at (mostly by guesswprk):
val reader = new MapFile.Reader(FileSystem.getLocal(new Configuration()), ".../apache-nutch-1.8/crawl/segments/20140711115438/content/part-00000", new Configuration())
var key = null
var value = null
reader.next(key, value) // test for a single value
println(key)
println(value)
However, I am getting this exception when I run it:
Exception in thread "main" java.lang.NullPointerException
at org.apache.hadoop.io.SequenceFile$Reader.next(SequenceFile.java:1873)
at org.apache.hadoop.io.MapFile$Reader.next(MapFile.java:517)
I am not sure how to work with a MapFile.Reader, specifically, what constructor parameters I am supposed to pass to it. What Configuration objects am I supposed to pass in? Is that the correct FileSystem? And is that the data file I'm interested in?
Scala:
val conf = NutchConfiguration.create()
val fs = FileSystem.get(conf)
val file = new Path(".../part-00000/data")
val reader = new SequenceFile.Reader(fs, file, conf)
val webdata = Stream.continually {
val key = new Text()
val content = new Content()
reader.next(key, content)
(key, content)
}
println(webdata.head)
Java:
public class ContentReader {
public static void main(String[] args) throws IOException {
Configuration conf = NutchConfiguration.create();
Options opts = new Options();
GenericOptionsParser parser = new GenericOptionsParser(conf, opts, args);
String[] remainingArgs = parser.getRemainingArgs();
FileSystem fs = FileSystem.get(conf);
String segment = remainingArgs[0];
Path file = new Path(segment, Content.DIR_NAME + "/part-00000/data");
SequenceFile.Reader reader = new SequenceFile.Reader(fs, file, conf);
Text key = new Text();
Content content = new Content();
// Loop through sequence files
while (reader.next(key, content)) {
try {
System.out.write(content.getContent(), 0,
content.getContent().length);
} catch (Exception e) {
}
}
}
}
Alternatively, you can use org.apache.nutch.segment.SegmentReader (example).

set windows PATH environment variable at runtime in Java

I have a java program that fires off an executable using the Runtime.exec() method. I'm using the variant that takes in a set of command line params as one argument, and some environment variables as another argument.
The environment variable I'm tryign to set is path, so i'm passing in "PATH=C:\some\path". This does not work. Is there some trick to this or any alternatives. I am stuck to Java 1.4 unfortunately.
Use getenv to get the environment and fix it up then use a flavour of exec to do the exec.
This works with a batch file that has path in it.
package p;
import java.util.*;
public class Run {
static String[] mapToStringArray(Map<String, String> map) {
final String[] strings = new String[map.size()];
int i = 0;
for (Map.Entry<String, String> e : map.entrySet()) {
strings[i] = e.getKey() + '=' + e.getValue();
i++;
}
return strings;
}
public static void main(String[] arguments) throws Exception {
final Map<String, String> env = new HashMap<String, String>(System.getenv());
env.put("Path", env.get("Path") + ";foo");
final String[] strings=mapToStringArray(env);
Runtime.getRuntime().exec("cmd /C start foo.bat",strings);
}
}
If "PATH=C:\some\path" appears in your source code, it would be incorrect as it would be trying to escape the 's' and 'p' in that string, you'd use "PATH=C:\\some\\path" instead (escaping the slashes). Also, you don't want to pass it in as a string directly, but as an array of strings (likely with that as the only string in it).
If you want to change the Path variable on windows, you should take a look at JNI_Registry: http://www.trustice.com/java/jnireg/
It's a Java binding to the Windows Registry API and comes with a very small footprint.
I have used it for my current project and it works just fine.
One solution might be to add an additional command to "exec" where you set the path ... as in the example found here:
http://www.neowin.net/forum/topic/620450-java-runtimegetruntimeexec-help/
excerpt:
cmd = new String[7];
cmd[0] = "cmd";
cmd[1] = "/C";
cmd[2] = "set PATH=C:\\Program Files\\Java\\jdk1.6.0_04\bin";
cmd[3] = "copy " + "\"" +path + "\\" +name+ "\"" + " C:\\java";
cmd[4] = "chdir C:\\java";
cmd[5] = "javac *.java";
cmd[6] = "jar cmf mainClass.txt"+" name"+".jar *.class";
try{
Runtime.getRuntime().exec(cmd);

Categories

Resources