I have an issue trying to use openssl command to encrypt and decrypt varchar2 variables with text data and multiples white spaces between.
I can encrypt/decrypt, but the output remove multiple white spaces inside the decrypted text. I've tried several ways process the text with urlencode/urldecode and base64encode/base64decode. But the decrypted text is always the same. Maybe white spaces doesn't matter for openssl or what I am doing wrong?
--Code:
--Encrypt
DECLARE
l_output DBMS_OUTPUT.chararr;
l_lines INTEGER := 1000;
key_value VARCHAR2(200) := 'thisisthekeytoencryptdecrypt';
command VARCHAR2(1000);
text_encrypt VARCHAR2(1000);
text_value VARCHA2(50):= '11 22 444';
BEGIN
command:='echo '||texto_value||'|/usr/bin/openssl enc -aes-256-cbc -e -base64 -A -pass pass:'||key_value;
host_command(comand);
DBMS_OUTPUT.get_lines(l_output, l_lines);
FOR i IN 1 .. l_lines LOOP
text_encrypt:=text_encrypt||substr(l_output(i),14);
END LOOP;
DBMS_OUTPUT.put_line('text_Encrypted:'|| text_encrypt);
END;
/--
--Decrypt
DECLARE
l_output DBMS_OUTPUT.chararr;
l_lines INTEGER := 1000;
key_value VARCHAR2(200) := 'thisisthekeytoencryptdecrypt';
command VARCHAR2(1000);
text_encrypt VARCHAR2(1000) := 'U2FsdGVkX19ljEkuiUDkNthSfcboezhyYg6+wLO3HC8=';
text_value VARCHAR2(50);
BEGIN
command:='echo '||text_encrypt||'|/usr/bin/openssl enc -aes-256-cbc -d -a -base64 -A -pass pass:'||key_value;
host_command(command);
DBMS_OUTPUT.get_lines(l_output, l_lines);
FOR i IN 1 .. l_lines LOOP
text_value:=text_value||substr(l_output(i),14);
END LOOP;
DBMS_OUTPUT.put_line('text_decrypted:'|| text_value);
END;
/
--host_command: java stored procedure
-- https://oracle-base.com/articles/8i/shell-commands-from-plsql
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "Host" AS
import java.io.*;
public class Host {
public static void executeCommand(String command) {
try {
String[] finalCommand;
if (isWindows()) {
finalCommand = new String[4];
// Use the appropriate path for your windows version.
//finalCommand[0] = "C:\\winnt\\system32\\cmd.exe"; // Windows NT/2000
finalCommand[0] = "C:\\windows\\system32\\cmd.exe"; // Windows XP/2003
//finalCommand[0] = "C:\\windows\\syswow64\\cmd.exe"; // Windows 64-bit
finalCommand[1] = "/y";
finalCommand[2] = "/c";
finalCommand[3] = command;
}
else {
finalCommand = new String[3];
finalCommand[0] = "/bin/sh";
finalCommand[1] = "-c";
finalCommand[2] = command;
}
final Process pr = Runtime.getRuntime().exec(finalCommand);
pr.waitFor();
new Thread(new Runnable(){
public void run() {
BufferedReader br_in = null;
try {
br_in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String buff = null;
while ((buff = br_in.readLine()) != null) {
System.out.println("Process out :" + buff);
try {Thread.sleep(100); } catch(Exception e) {}
}
br_in.close();
}
catch (IOException ioe) {
System.out.println("Exception caught printing process output.");
ioe.printStackTrace();
}
finally {
try {
br_in.close();
} catch (Exception ex) {}
}
}
}).start();
new Thread(new Runnable(){
public void run() {
BufferedReader br_err = null;
try {
br_err = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
String buff = null;
while ((buff = br_err.readLine()) != null) {
System.out.println("Process err :" + buff);
try {Thread.sleep(100); } catch(Exception e) {}
}
br_err.close();
}
catch (IOException ioe) {
System.out.println("Exception caught printing process error.");
ioe.printStackTrace();
}
finally {
try {
br_err.close();
} catch (Exception ex) {}
}
}
}).start();
}
catch (Exception ex) {
System.out.println(ex.getLocalizedMessage());
}
}
public static boolean isWindows() {
if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1)
return true;
else
return false;
}
};
/
The problem is that you're passing this through the shell:
command:='echo '||texto_value||'|/usr/bin/openssl enc -aes-256-cbc -e -base64 -A -pass pass:'||key_value;
The shell is removing the spaces before sending to the echo command. You'll need to put quotes around the value, probably along these lines (note placement of "):
command:='echo "'||texto_value||'"|/usr/bin/openssl enc -aes-256-cbc -e -base64 -A -pass pass:'||key_value;
Related
From my Tomcat's servlet I execute an https connection to an external servlet.
This is the code:
HttpsURLConnection hpcon = null;
try {
URL url = new URL(surl);
hpcon = (HttpsURLConnection) url.openConnection();
hpcon.setRequestMethod("POST");
hpcon.setDoInput(true);
hpcon.setDoOutput(true);
hpcon.setUseCaches(false);
hpcon.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
OutputStreamWriter wr = new OutputStreamWriter(hpcon.getOutputStream());
String params = "user=" + URLEncoder.encode(user, "UTF-8");
params += "&psswd=" + URLEncoder.encode(pssw, "UTF-8");
params += "&metodo=" + URLEncoder.encode(metodo, "UTF-8");
wr.write(params);
wr.flush();
wr.close();
hpcon.connect();
int respCode = hpcon.getResponseCode();
if (respCode == 200) {
BufferedReader br = new BufferedReader(new InputStreamReader(hpcon.getInputStream()));
String response = "";
String output;
while ((output = br.readLine()) != null) {
response += output;
}
if (response.indexOf("-") > 0) {
response = "-12";
System.out.println("ret = -12 - response = " + response);
}
br.close();
} else {
ret = "-11";
System.out.println("ret = -11 - respCode = " + respCode);
}
} catch (Exception e) {
e.printStackTrace();
ret = "-10";
System.out.println("ret = -10");
} finally {
if (hpcon != null) {
hpcon.disconnect();
}
}
Where surl is the full url of a servlet present in a different domain and the three parameters are read from a db table (the third really is fixed and is the operation that is make by the external servlet).
The result is:
ret = -11 - respCode = 404
Before make the connection I turn off the certificate's verify using the above code:
try {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
} catch (Exception e) {
e.printStackTrace();
}
If I execute the same servlet manually from a browser with parameters in get mode all run correctly.
I tried to execute it on my code using the get mode and passing the three parameters in query string, but the result is the same.
How can I do to resolve the problem?
I have to run two commands using Process in asp.net as given below and the first command runs successfully while running the second command gets hung at result = p.StandardOutput.ReadToEnd()
How to implement this to run both commands successfully?
private static string FFMPEG_EXE_PATH = #"D:\ffmpeg\bin\ffmpeg.exe";
private static string FFPROBE_EXE_PATH = #"D:\ffmpeg\bin\ffprobe.exe";
protected void Page_Load(object sender, EventArgs e)
{
string firstArgs = #"-hide_banner -show_format -show_streams -pretty D:\Video\dolbycanyon.m4v";
var result1 = Execute(FFPROBE_EXE_PATH, firstArgs);
string secondArgs = #"-hide_banner -ss 00:00:05 -i D:\Video\dolbycanyon.m4v -r 1 -t 1 -f image2 D:\Video\test.jpg";
var result2 = Execute(FFMPEG_EXE_PATH, secondArgs);
}
private string Execute(string exePath, string parameters)
{
string result = String.Empty;
using (Process p = new Process())
{
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = exePath;
p.StartInfo.Arguments = parameters;
p.Start();
result = p.StandardOutput.ReadToEnd(); // the application hung here for the second command
p.WaitForExit();
}
return result;
}
I have changed the Execute method to as below and it worked for both commands.
public string Execute(string path, string args, int timeoutMs)
{
using (var outputWaitHandle = new ManualResetEvent(false))
{
using (var process = new Process())
{
process.StartInfo = new ProcessStartInfo(path);
process.StartInfo.Arguments = args;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
var sb = new StringBuilder(1024);
process.OutputDataReceived += (sender, e) =>
{
sb.AppendLine(e.Data);
if (e.Data == null)
{
outputWaitHandle.Set();
}
};
process.Start();
process.BeginOutputReadLine();
process.WaitForExit(timeoutMs);
outputWaitHandle.WaitOne(timeoutMs);
process.CancelOutputRead();
return sb.ToString();
}
}
}
I am getting this error when I am decrypting a file
I am using PBKDF2 to convert a passphrase to a key and then using it. The encryption is working good but when I am trying to decrypt the same file it is giving the below error. The decrypted file gives a correct data except for the last few lines(probably the padding area). I have debugged it by outputting the IV and key while encrypting and decrypting and they both are the same but the error still exists.
public class FileEncryptorSkeleton{
private static final String progName = "FileEncryptor";
private static final int bufSize = 128;
/**
* #param args
*/
public static void main(String[] args) throws UnsupportedEncodingException {
BufferedInputStream in = null; // A buffered input stream to read from
BufferedOutputStream out = null; // And a buffered output stream to write to
SecretKeyFactory kf = null; // Something to create a key for us
KeySpec ks = null; // This is how we specify what kind of key we want it to generate
byte[] salt = new byte[20]; // Some salt for use with PBKDF2, only not very salty
SecretKey key = null; // The key that it generates
Cipher cipher = null; // The cipher that will do the real work
SecretKeySpec keyspec = null; // How we pass the key to the Cipher
int bytesRead = 0; // Number of bytes read into the input file buffer
byte[] iv = new byte[16];
// First, check the user has provided all the required arguments, and if they haven't, tell them then exit
if(args.length != 4) {
printUsageMessage(); System.exit(1);
}
// Open the input file
try {
in = new BufferedInputStream(new FileInputStream(args[1]));
} catch (FileNotFoundException e) {
printErrorMessage("Unable to open input file: " + args[1], null);
System.exit(1);
}
// And then the output file
try {
out = new BufferedOutputStream(new FileOutputStream(args[2]));
} catch (FileNotFoundException e) {
printErrorMessage("Unable to open output file: " + args[2], e);
System.exit(1);
}
try {
kf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
}
// Set up a KeySpec for password-based key generation of a 128-bit key
ks = new PBEKeySpec(args[3].toCharArray(), salt, 1000, 128);
// Now run the passphrase through PBKDF2 to get the key
try {
key = kf.generateSecret(ks);
}catch(InvalidKeySpecException e){
System.exit(1);
}
// Get the byte encoded key value as a byte array
byte[] aeskey = key.getEncoded();
// Now generate a Cipher object for AES encryption in ECBC mode with PKCS #5 padding
// Use ECB for the first task, then switch to CBC for versions 2 and 3
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
printErrorMessage("No Such Algorithm Exception when creating main cipher", e);
System.exit(2);
} catch (NoSuchPaddingException e) {
printErrorMessage("No Such Padding Exception when creating main cipher",e);
System.exit(2);
}
// Set a variable to indicate whether we're in encrypt or decrypt mode, based upon args[0]
int cipherMode = -1;
char mode = Character.toLowerCase(args[0].charAt(0));
switch (mode) {
case 'e' : cipherMode = Cipher.ENCRYPT_MODE; break;
case 'd' : cipherMode = Cipher.DECRYPT_MODE; break;
default: printUsageMessage(); System.exit(1);
}
// Set up a secret key specification, based on the 16-byte (128-bit) AES key array previously generated
keyspec = new SecretKeySpec(aeskey, "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv);
// Now initialize the cipher in the right mode, with the keyspec and the ivspec
try {
cipher.init(cipherMode, keyspec,ivspec);
} catch (InvalidKeyException e) {
printErrorMessage("Invalid Key Spec",e); System.exit(2);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
}
// Set up some input and output byte array buffers
byte[] inputBuffer = new byte[bufSize];
byte[] outputBuffer = null;
// "Prime the pump" - we've got to read something before we can encrypt it
// and not encrypt anything if we read nothing.
try {
bytesRead = in.read(inputBuffer);
} catch (IOException e) {
printErrorMessage("Error reading input file " + args[1],e); System.exit(1);
}
// As long as we've read something, loop around encrypting, writing and reading
// bytesRead will be zero if nothing was read, or -1 on EOF - treat them both the same
while (bytesRead > 0) {
// Now encrypt this block
outputBuffer = cipher.update(inputBuffer.toString().getBytes("UTF-8"));
// Write the generated block to file
try {
out.write(outputBuffer);
} catch (IOException e) {
printErrorMessage("Error writing to output file " + args[2],e); System.exit(1);
}
// And read in the next block of the file
try {
bytesRead = in.read(inputBuffer);
} catch (IOException e) {
printErrorMessage("Error reading input file " + args[1],e); System.exit(1);
}
}
try {
// Now do the final processing
outputBuffer =cipher.doFinal(inputBuffer.toString().getBytes("UTF-8"));
cipher.init(cipherMode, keyspec,ivspec);
System.out.println(ivspec+" "+cipherMode+" "+keyspec);
} catch (IllegalBlockSizeException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
}
// Write the final block of output
try {
out.write(outputBuffer);
} catch (IOException e) {
printErrorMessage("Error on final write to output file " + args[2],e); System.exit(1);
}
// Close the output files
try {
in.close();
out.close();
} catch (IOException e) {
printErrorMessage("Error closing file", e);
}
// If we were continuing beyond this point, we should really overwrite key material, drop KeySpecs, etc.
}
/**
* Print an error message on , optionally picking up additional detail from
* a passed exception
* #param errMsg
* #param e
*/
private static void printErrorMessage(String errMsg, Exception e) {
System.err.println(errMsg);
if (e != null)
System.err.println(e.getMessage());
}
/**
* Print a usage message
*/
private static void printUsageMessage() {
System.out.println(progName + " $Revision: 1.1 $: Usage: " + progName + " E/D infile outfile passphrase");
}
}
Oct 18, 2019 11:27:46 PM FileEncryptorSkeleton main
SEVERE: null
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at FileEncryptorSkeleton.main(FileEncryptorSkeleton.java:174)
Both the Cipher#update- and Cipher#doFinal-method use inputBuffer.toString(), which only contains the name of the object's class and the hashcode and not the actual data in the buffer.
It would be correct to read the first bytesRead bytes from the inputBuffer-byte[] (which were previously read from the in-BufferedInputStream) and process them (Cipher#update):
outputBuffer = cipher.update(inputBuffer, 0, bytesRead);
The loop containing the cipher#update-call is only left when no byte has been read to the inputBuffer-byte[], so that for the final processing applies (Cipher#doFinal):
outputBuffer = cipher.doFinal();
In addition, the second cipher#init-call immediately after the cipher#doFinal-call is unnecessary (Cipher#init).
Simple enough problem but it's been driving me crazy.
In my program I have a TextArea, defined as:
<TextArea fx:id="output" editable="false" prefHeight="300.0" prefWidth="200.0" text="Output" GridPane.columnSpan="2" GridPane.rowIndex="4" />
#FXML private TextArea output;
...
public void initialize(URL url, ResourceBundle rb) {
output.setText("Test"); //Test appears correctly in output
...
}
#FXML
public void download() {
String outputTemplate = templateField.getText();
String url = urlField.getText();
System.out.println("Downloading from " + url);
try {
Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url);
BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); //Prints as expected
output.appendText(line + "\n"); //Has no effect
}
} catch (IOException e) {
e.printStackTrace();
}
}
Any ideas on how to get the text to appear would be great, I've done this before on different programs, just for some reason, this time it's being cantankerous
EDIT: Upon further tinkering, it actually will print out the results, but only after the Process ends and it exits the loop.
The text shown in the UI changes on a layout pulse. Layout pulses are done on the JavaFX application thread. Event handlers, like your download method run on the same thread effectively preventing it from doing any layouting or processing and other events until it completes. This is why you shouldn't block this thread with longrunning tasks, but execute them on a different thread.
Since updates to the UI should be done from the application thread, use Platform.runLater to append the text:
#FXML
public void download() {
String outputTemplate = templateField.getText();
String url = urlField.getText();
Runnable r = () -> {
System.out.println("Downloading from " + url);
try {
Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url);
BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); //Prints as expected
final String printText = line + "\n";
// append the line on the application thread
Platform.runLater(() -> output.appendText(printText));
}
} catch (IOException e) {
e.printStackTrace();
}
};
// run task on different thread
Thread t = new Thread(r);
t.start();
}
The problem is that you're doing this in the main thread. So stage can not be updated, until the cycle is finished. Try it in new thread:
#FXML
public void download() {
Task<Void> task = new Task<Void>() {
#Override
protected Void call() {
String outputTemplate = templateField.getText();
String url = urlField.getText();
System.out.println("Downloading from " + url);
try {
Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url);
BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // Prints as expected
output.appendText(line + "\n"); // Has no effect
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
new Thread(task).start();
}
I want to compile a java file and exec its class in another class ( ← This class is a #service of a Spring MVC project ).
The service code is:
#Service
public class MRServiceImp implements MRService {
#Override
public String submitMR(int id, String fd) {
try {
// compile the java file
String[] cmd = {"javac", "P" + id + ".java"};
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.directory(new File(fd));
Process p = pb.start();
// exec the class file
String[] execmd = {"java", "P" + pz_id};
ProcessBuilder epb = new ProcessBuilder(execmd);
epb.directory(new File(fd));
p = epb.start();
// get normal output
BufferedReader pin = new BufferedReader(new InputStreamReader(p.getInputStream()));
String ptmp = pin.readLine();
while (ptmp != null) {
pout = pout == null ? ptmp + '\n' : pout + ptmp + '\n';
ptmp = pin.readLine();
}
// get error output
pin = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String wout = null;
ptmp = pin.readLine();
while (ptmp != null) {
wout = wout == null ? ptmp + '\n' : wout + ptmp + '\n';
ptmp = pin.readLine();
}
// print output
System.out.println(pout);
System.out.println(wout);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null; // for test
}
When this Service is invoked, I always get a Error: Could not find or load main class: P[id]
I cd theFilePath, the P[id].class file is existing.
And I can run java P[id] successfully in theFilePath.
And I try to replace ProcessBuilder with Runtime, like:
#Service
public class MRServiceImp implements MRService {
#Override
public String submitMR(int id, String fd) {
try {
// compile the java file
String[] cmd = {"javac", "P" + id + ".java"};
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.directory(new File(fd));
Process p = pb.start();
// exec the class file
String execmd = "java", fd + "/P" + pz_id;
p = Runtime.getRuntime().exec(execmd);
// get normal output
BufferedReader pin = new BufferedReader(new InputStreamReader(p.getInputStream()));
String ptmp = pin.readLine();
while (ptmp != null) {
pout = pout == null ? ptmp + '\n' : pout + ptmp + '\n';
ptmp = pin.readLine();
}
// get error output
pin = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String wout = null;
ptmp = pin.readLine();
while (ptmp != null) {
wout = wout == null ? ptmp + '\n' : wout + ptmp + '\n';
ptmp = pin.readLine();
}
// print output
System.out.println(pout);
System.out.println(wout);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null; // for test
}
I get the same Error again T^T
IDE is sts-bundle, server is tomcat8
I know what is wrong here.
pb.start(); does not mean the command of pb will be executed immediately.
So if I set pb of command javac hello.java; set epb of command java hello
And I call pb.start(); epb.start(); continuously, I will get an Error: could not find or load main class: hello, because when I exec epb.start(); The former command(pb.start) may have not been executed!
I got 2 solution:
First: set a finally field and exec epb.start() in this field, like:
#Service
public class MRServiceImp implements MRService {
#Override
public String submitMR(int id, String fd) {
try {
// compile the java file
String[] cmd = {"javac", "P" + id + ".java"};
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.directory(new File(fd));
Process p = pb.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// exec the class file
String[] execmd = {"java", "P" + pz_id};
ProcessBuilder epb = new ProcessBuilder(execmd);
epb.directory(new File(fd));
Process p = epb.start();
}
return null; // for test
}
Second: a trick of bash
#Service
public class MRServiceImp implements MRService {
#Override
public String submitMR(int id, String fd) {
try {
// compile & exec the java file
String[] cmd = {"/bin/bash"};
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.directory(new File(fd));
Process p = pb.start();
BufferedWriter pbw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
pbw.write("javac *.java;java P" + pz_id+";exit;");
pbw.newLine();
pbw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null; // for test
}
I use the second one.