JAI tiff image conversion producing bigger file size on windows 7 - windows-7

Trying to compress the image using JAI with TIFF format. It works fine on Windows XP, But it produces 10 times bigger size file on Windows 7 compared to Windows XP.
Using JAI 1.1 and JRE 1.6_0_16
What might be the issue? Appreciate your assistance.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Locale;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import com.sun.media.imageio.plugins.tiff.TIFFImageWriteParam;
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
File image = new File("abc.tiff");
File tempFile = new File("compressed.tiff");
try {
BufferedImage bi = ImageIO.read(image);
byte[] tiffArray = toTiff(bi, tempFile,"packBits" );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static byte[] toTiff(BufferedImage bi, File tempFile, String compType) {
byte[] bImg = null;
try{
tempFile.delete();
String format = "TIF";
Iterator writers = ImageIO.getImageWritersByFormatName(format);
if(writers == null || !writers.hasNext()) {
throw new IllegalArgumentException("Unsupported format (" + format + ")");
}
ImageWriter writer = (ImageWriter)writers.next();
IIOImage iioImg = new IIOImage(bi, null, null);
TIFFImageWriteParam writeParam = new TIFFImageWriteParam(Locale.ENGLISH);
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writeParam.setCompressionType(compType);
ImageOutputStream ios = ImageIO.createImageOutputStream(tempFile);
writer.setOutput(ios);
writer.write(null, iioImg, writeParam);
ios.close();
writer.dispose();
bImg = readImage(tempFile);
}catch(Exception e){
e.printStackTrace();
}
return bImg;
}
public static byte[] readImage(File f) throws Exception {
byte[] bImg = null;
try {
long fLength = f.length();
if(fLength > Integer.MAX_VALUE){
throw new RuntimeException("File is too large to upload....!");
}
bImg = new byte[(int)fLength];
FileInputStream fin = new FileInputStream(f);
fin.read(bImg);
fin.close();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
return bImg;
}
}

Related

Android 11 EPERM (Operation not permitted)

Hello
I try copy folder assets to external directory but getting permition error from android 11 (Api30).
But Its working well when copy or create folder to internal storage.
please help how to fix.
This is error code;
/com.strong.choosedirectory E/Tag: /storage/0E1A-2619/CTV_USB_EU/channel_list_sub.bin: open failed: EPERM (Operation not permitted)
This is main_activity code;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.krunal.choosedirectory.R;
import com.krunal.choosedirectory.databinding.ActivityMainBinding;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import pub.devrel.easypermissions.EasyPermissions;
import static com.krunal.choosedirectory.ClsGlobal.ClsGlobal.SELECT_DIRECTORY;
import static com.krunal.choosedirectory.ClsGlobal.ClsGlobal.requestPermission;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
requestPermission(MainActivity.this);
binding.btnSelectDirectory.setOnClickListener(v -> {
Intent i = new Intent(this, SelectDirectoryActivity.class);
startActivityForResult(i, SELECT_DIRECTORY);
});
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Forward results to EasyPermissions
EasyPermissions.onRequestPermissionsResult(requestCode,
permissions, grantResults, this);
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == SELECT_DIRECTORY && data != null) {
if (data != null) {
new File(data.getStringExtra("SelectedPath") + "/CTV_USB_EU/").mkdirs();
/////
requestPermission(MainActivity.this);
/////
binding.tvDrSelected.setText(data.getStringExtra("SelectedPath"));
// out = new FileOutputStream("".toString() + (data.getStringExtra("SelectedPath")) + fileName);
}
}
super.onActivityResult(requestCode, resultCode, data);
Button buton = (Button) findViewById(R.id.buton);
buton.setOnClickListener(new View.OnClickListener() { //butona tıklandığı an yapılacaklar
#Override
public void onClick(View view) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("test tiklama calisti")
.setMessage("Seçilen USB Aygıtı " + (data.getStringExtra("SelectedPath")))
.setPositiveButton("Tamam", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Tamam butonuna basılınca yapılacak olanlar
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("Files");
} catch (Exception e) {
Log.e("Tag", e.getMessage());
}
for (String fileName : files) {
System.out.println("Files=>" + fileName);
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open("Files/" + fileName);
out = new FileOutputStream("".toString() + "/" + (data.getStringExtra("SelectedPath")) + "/CTV_USB_EU/" + fileName);
copyFiles(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
Log.e("Tag", e.getMessage());
}
}
// copyAssets();
}
})
.setNegativeButton("İptal", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// İptal butonuna basınca yapılacak olanlar
}
})
.show();
String isim;
isim = ("".toString() + (data.getStringExtra("SelectedPath")));
System.out.println((isim));
}
});
}
private void copyFiles (InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
public void mkDir (String args[])
{
// create an abstract pathname (File object)
File f = new File(toString(), "File");
// check if the directory can be created
// using the abstract path name
if (f.mkdir()) {
Log.d("BG", "Mkdir return: " );
// display that the directory is created
// as the function returned true
System.out.println("Directory is created");
} else {
// display that the directory cannot be created
// as the function returned false
System.out.println("Directory cannot be created");
}
}
}
lklklekflkpewkflkeşlkfeşwf
ewf
ewf
ew
fe
f
ewferw
g
wr
gşirlglwrlg
wrg
wg
e
glrşklgşrlg
w
grlwr
lg
wrlgirl
g
rwglşrwkg
rwk
g
wrgl
rlg
irlg
lrw
gl
wrlg
rwilg
riwlg
irwlg
irw

Spring Check if an image has a qr code then scan it [duplicate]

First of all, I read through all those topics how to use Zxing in Java but always got errors with missing com.google.zxing.client.j2se.* (I loaded the zxing core-3.2.1.jar in eclipse and all other zxing packages work unless j2se) or just found solutions for creating qr images...
My aim is to write one single method which gets an image file finds the qr code in this image, decodes the qr code and returns the string, basically it should be something like the following:
import com.google.zxing.*;
public class QRCode {
/*
* ...
*/
public String getDecodedString(SomeStandardImageType photo){
// detect the qr code in a photo
// create qr image from detected area in photo
// decode the new created qr image and return the string
return "This is the decoded dataString from the qr code in the photo";
}
}
To sum up the method should get an image file like the following
and should return the url or if failed just "".
The code should be compatible with Zxing 3.2.1.
Edit: The question is solved. For others who are interested in this I want to say that it is important to add both external jars core-3.2.1.jar and javase-3.2.1.jar to external jars. The answer by me works without the latter but depends on android image libs.
here is the code to create the Qr-Code and read Message from Qr-code
you need the build the zxing library
main describe the qr-code creation and qr-code extraction
package com.attendance.mark;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class QRCode {
/**
*
* #param args
* #throws WriterException
* #throws IOException
* #throws NotFoundException
*/
public static void main(String[] args) throws WriterException, IOException,
NotFoundException {
String qrCodeData = "student3232_2015_12_15_10_29_46_123";
String filePath = "F:\\Opulent_ProjectsDirectory_2015-2016\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp0\\wtpwebapps\\AttendanceUsingQRCode\\QRCodes\\student3232_2015_12_15_10_29_46_123";
String charset = "UTF-8"; // or "ISO-8859-1"
Map<EncodeHintType, ErrorCorrectionLevel> hintMap = new HashMap<EncodeHintType, ErrorCorrectionLevel>();
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
createQRCode(qrCodeData, filePath, charset, hintMap, 200, 200);
System.out.println("QR Code image created successfully!");
System.out.println("Data read from QR Code: "
+ readQRCode(filePath, charset, hintMap));
}
/***
*
* #param qrCodeData
* #param filePath
* #param charset
* #param hintMap
* #param qrCodeheight
* #param qrCodewidth
* #throws WriterException
* #throws IOException
*/
public static void createQRCode(String qrCodeData, String filePath,
String charset, Map hintMap, int qrCodeheight, int qrCodewidth)
throws WriterException, IOException {
BitMatrix matrix = new MultiFormatWriter().encode(
new String(qrCodeData.getBytes(charset), charset),
BarcodeFormat.QR_CODE, qrCodewidth, qrCodeheight);
MatrixToImageWriter.writeToFile(matrix, filePath.substring(filePath
.lastIndexOf('.') + 1), new File(filePath));
}
/**
*
* #param filePath
* #param charset
* #param hintMap
*
* #return Qr Code value
*
* #throws FileNotFoundException
* #throws IOException
* #throws NotFoundException
*/
public static String readQRCode(String filePath, String charset, Map hintMap)
throws FileNotFoundException, IOException, NotFoundException {
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(
new BufferedImageLuminanceSource(
ImageIO.read(new FileInputStream(filePath)))));
Result qrCodeResult = new MultiFormatReader().decode(binaryBitmap, hintMap);
return qrCodeResult.getText();
}
}
I now read deeper into Zxing and the following code will work with Zxing v3.2.1 (This code works without javase lib)
// Imports
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.LuminanceSource;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
// Interesting method
public static String decodeQRImage(String path) {
Bitmap bMap = BitmapFactory.decodeFile(path);
String decoded = null;
int[] intArray = new int[bMap.getWidth() * bMap.getHeight()];
bMap.getPixels(intArray, 0, bMap.getWidth(), 0, 0, bMap.getWidth(),
bMap.getHeight());
LuminanceSource source = new RGBLuminanceSource(bMap.getWidth(),
bMap.getHeight(), intArray);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Reader reader = new QRCodeReader();
try {
Result result = reader.decode(bitmap);
decoded = result.getText();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
}
return decoded;
}
This code works fine for me. Hope it helps just import the necessary packages and it should work
public class QR_Reader extends JFrame implements Runnable, ThreadFactory {
private static final long serialVersionUID = 6441489157408381878L;
private Executor executor = Executors.newSingleThreadExecutor(this);
private Webcam webcam = null;
private WebcamPanel panel = null;
String s;
public QR_Reader() {
super();
setLayout(new FlowLayout());
setTitle("Reading QR Code");
Dimension size = WebcamResolution.QVGA.getSize();
webcam = Webcam.getWebcams().get(0);
webcam.setViewSize(size);
panel = new WebcamPanel(webcam);
panel.setPreferredSize(size);
add(panel);
pack();
setVisible(true);
setResizable(false);
executor.execute(this);
}
#Override
public void run() {
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Result result = null;
BufferedImage image = null;
if (webcam.isOpen()) {
if ((image = webcam.getImage()) == null) {
continue;
}
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
result = new MultiFormatReader().decode(bitmap);
} catch (NotFoundException e) {
// fall thru, it means there is no QR code in image
}
}
if (result != null) {
String time_then=result.getText(); //this is the text extracted from QR CODE
webcam.close();
this.setVisible(false);
this.dispose();
try {
new Compare().C_Main(time_then);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} while (true);
}
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "example-runner");
t.setDaemon(true);
return t;
}
void QRC_Main() {
new QR_Reader();
}
}

Oracle : Send latest insert/update to JMS

I have an insert/update trigger for a Oracle table.
Is there a way to send the details of the affected row(all columns) as a message to JMS?
I can write a Java Program, 'loadjava' that and call from the trigger.
Does this way affect performance?
Is there any native way of achieving this?
There is indeed a native way: use AQ JMS from PL/SQL, see https://docs.oracle.com/database/121/ADQUE/jm_exmpl.htm#ADQUE1600. In short you create an AQ queue with a JMS payload type; then you can post messages with PL/SQL from the trigger. An external Java client can connect to the database and read the messages with JMS.
I don't know how much a call into Java would affect performance, but I try to avoid it. It was a nice idea but it never really caught on, so it remains a fringe case and at least early on there were always issues. PL/SQL on the other hand works.
If you need to send data to another message queue product (tags activemq and mq) you can read the messages in Java and forward them. It adds an extra step, but it is straightforward.
loadjava have many problems and not stable if there is many classes loaded and many business, take a look Calling Java from Oracle, PLSQL causing oracle.aurora.vm.ReadOnlyObjectException
Oracle AQ as i know is not free.
I have implemented the same need after trying many possibilities by creating only 1 class loaded to oracle with loadjava which is called as a procedure by a trigger and have the responsability to call an external java program with all needed parameters and log external process output to a table, as below.
i have encoded text mesage to BASE64 because i used JSON format and some specials caracters can causes problems as a parameters to external java program.
i have used "#*#jms_separator#*#" as a separator in the sent parameter string to parse the content if i need to send many parameters to the external program.
the whole duration of ShellExecutor.shellExec is around 500ms and running since 1 year without any problem.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Arrays;
import java.util.concurrent.FutureTask;
import sun.misc.BASE64Encoder;
public class ShellExecutor {
static {
System.setProperty("file.encoding", "UTF-8");
}
private static final String INSERT_LOGS_SQL = "INSERT INTO JMS_LOG (TEXT_LOG) VALUES (?) ";
private static final String DEFAULT_CONNECTION = "jdbc:default:connection:";
public static String SQLshellExec(String command) throws Exception {
long start = System.currentTimeMillis();
StringBuffer result = new StringBuffer();
ShellExecutor worker = new ShellExecutor();
try {
worker.shellExec(command, result);
} finally {
result.append("exe duration : " + (System.currentTimeMillis() - start + "\n"));
Connection dbConnection = null;
PreparedStatement logsStatement = null;
try {
dbConnection = DriverManager.getConnection(DEFAULT_CONNECTION);
logsStatement = dbConnection.prepareStatement(INSERT_LOGS_SQL);
logsStatement.clearParameters();
Clob clob = dbConnection.createClob();
clob.setString(1, result.toString());
logsStatement.setClob(1, clob);
logsStatement.executeUpdate();
} finally {
if (logsStatement != null) {
try {
logsStatement.close();
} catch (Exception e) {
}
}
}
}
return result.substring(result.length() - 3090);
}
public void shellExec(String command, StringBuffer result) throws Exception {
Process process = null;
int exit = -10;
try {
InputStream stdout = null;
String[] params = command.split("#*#jms_separator#*#");
BASE64Encoder benc = new BASE64Encoder();
for (int i = 0; i < params.length; i++) {
if (params[i].contains("{") || params[i].contains("}") || params[i].contains("<")
|| params[i].contains("/>")) {
params[i] = benc.encodeBuffer(params[i].getBytes("UTF-8"));
}
}
result.append("Using separator : " + "#*#jms_separator#*#").append("\n")
.append("Calling : " + Arrays.toString(params)).append("\n");
ProcessBuilder pb = new ProcessBuilder(params);
pb.redirectErrorStream(true);
process = pb.start();
stdout = process.getInputStream();
LogStreamReader lsr = new LogStreamReader(stdout, result);
FutureTask<String> stdoutFuture = new FutureTask<String>(lsr, null);
Thread thread = new Thread(stdoutFuture, "LogStreamReader");
thread.start();
try {
exit = process.waitFor();
} catch (InterruptedException e) {
try {
exit = process.waitFor();
} catch (Exception e1) {
}
}
stdoutFuture.get();
result.append("\n").append("exit code :").append(exit).append("\n");
if (exit != 0) {
throw new RuntimeException(result.toString());
}
} catch (Exception e) {
result.append("\nException(").append(e.toString()).append("):").append(e.getCause()).append("\n\n");
e.printStackTrace(System.err);
throw e;
} finally {
if (process != null) {
process.destroy();
}
}
}
}
class LogStreamReader implements Runnable {
private BufferedReader reader;
private StringBuffer result;
public LogStreamReader(InputStream is, StringBuffer result) {
this.reader = new BufferedReader(new InputStreamReader(is));
this.result = result;
}
public void run() {
try {
String line = null;
while ((line = reader.readLine()) != null) {
result.append(line).append("\n");
}
} catch (Exception e) {
result.append("\nException(").append(e.toString()).append("):").append(e.getCause()).append("\n\n");
e.printStackTrace(System.err);
} finally {
try {
reader.close();
} catch (IOException e) {
}
}
}
}
The class of the external Java program packaged as an executable with all needed librairies, a simple JMS sender :
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONObject;
import progress.message.jclient.ConnectionFactory;
import progress.message.jimpl.Connection;
public class JMSSender {
private static SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS");
public static void main(String[] args) throws Throwable {
doSend(args[0]);
}
public static void doSend(String text)
throws Throwable {
if (Base64.isBase64(text)) {
text = new String(Base64.decodeBase64(text));
}
String content = "\n\nsending message :" + text;
Connection con = null;
Session session = null;
try {
ConnectionFactory cf = new ConnectionFactory();
session = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination dest = session.createTopic(destination) ;
MessageProducer producer = session.createProducer(dest);
con.start();
JSONObject json = new JSONObject();
json.put("content", text);
json.put("date", sdf.format(new Date()));
TextMessage tm = session.createTextMessage(json.toString());
producer.send(tm);
content += " \n\n" + "sent message :" + json.toString();
} catch (Throwable e) {
content += " \n\n" + e.toString() + " \n\n" + Arrays.toString(e.getStackTrace());
if (e.getCause() != null) {
content += " \n\nCause : " + e.getCause().toString() + " \n\n"
+ Arrays.toString(e.getCause().getStackTrace());
}
e.printStackTrace(System.err);
throw e;
} finally {
write("steps on sending message : " + content);
if (session != null) {
try {
session.commit();
session.close();
} catch (Exception e) {
}
session = null;
}
if (con != null) {
try {
con.stop();
con.close();
} catch (Exception e) {
}
}
}
}
private static void write(String log) {
try {
if (System.out != null) {
System.out.println(log);
}
} catch (Exception e2) {
}
}
}

Apache CXF Interceptors: Unable to modify the response Stream in a Out Interceptor [duplicate]

I would like to modify an outgoing SOAP Request.
I would like to remove 2 xml nodes from the Envelope's body.
I managed to set up an Interceptor and get the generated String value of the message set to the endpoint.
However, the following code does not seem to work as the outgoing message is not edited as expected. Does anyone have some code or ideas on how to do this?
public class MyOutInterceptor extends AbstractSoapInterceptor {
public MyOutInterceptor() {
super(Phase.SEND);
}
public void handleMessage(SoapMessage message) throws Fault {
// Get message content for dirty editing...
StringWriter writer = new StringWriter();
CachedOutputStream cos = (CachedOutputStream)message.getContent(OutputStream.class);
InputStream inputStream = cos.getInputStream();
IOUtils.copy(inputStream, writer, "UTF-8");
String content = writer.toString();
// remove the substrings from envelope...
content = content.replace("<idJustification>0</idJustification>", "");
content = content.replace("<indicRdv>false</indicRdv>", "");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(content.getBytes(Charset.forName("UTF-8")));
message.setContent(OutputStream.class, outputStream);
}
Based on the first comment, I created an abstract class which can easily be used to change the whole soap envelope.
Just in case someone wants a ready-to-use code part.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.log4j.Logger;
/**
* http://www.mastertheboss.com/jboss-web-services/apache-cxf-interceptors
* http://stackoverflow.com/questions/6915428/how-to-modify-the-raw-xml-message-of-an-outbound-cxf-request
*
*/
public abstract class MessageChangeInterceptor extends AbstractPhaseInterceptor<Message> {
public MessageChangeInterceptor() {
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
}
protected abstract Logger getLogger();
protected abstract String changeOutboundMessage(String currentEnvelope);
protected abstract String changeInboundMessage(String currentEnvelope);
public void handleMessage(Message message) {
boolean isOutbound = false;
isOutbound = message == message.getExchange().getOutMessage()
|| message == message.getExchange().getOutFaultMessage();
if (isOutbound) {
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
IOUtils.closeQuietly(cs);
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
String currentEnvelopeMessage = IOUtils.toString(csnew.getInputStream(), "UTF-8");
csnew.flush();
IOUtils.closeQuietly(csnew);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Outbound message: " + currentEnvelopeMessage);
}
String res = changeOutboundMessage(currentEnvelopeMessage);
if (res != null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Outbound message has been changed: " + res);
}
}
res = res != null ? res : currentEnvelopeMessage;
InputStream replaceInStream = IOUtils.toInputStream(res, "UTF-8");
IOUtils.copy(replaceInStream, os);
replaceInStream.close();
IOUtils.closeQuietly(replaceInStream);
os.flush();
message.setContent(OutputStream.class, os);
IOUtils.closeQuietly(os);
} catch (IOException ioe) {
getLogger().warn("Unable to perform change.", ioe);
throw new RuntimeException(ioe);
}
} else {
try {
InputStream is = message.getContent(InputStream.class);
String currentEnvelopeMessage = IOUtils.toString(is, "UTF-8");
IOUtils.closeQuietly(is);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Inbound message: " + currentEnvelopeMessage);
}
String res = changeInboundMessage(currentEnvelopeMessage);
if (res != null) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Inbound message has been changed: " + res);
}
}
res = res != null ? res : currentEnvelopeMessage;
is = IOUtils.toInputStream(res, "UTF-8");
message.setContent(InputStream.class, is);
IOUtils.closeQuietly(is);
} catch (IOException ioe) {
getLogger().warn("Unable to perform change.", ioe);
throw new RuntimeException(ioe);
}
}
}
public void handleFault(Message message) {
}
private class CachedStream extends CachedOutputStream {
public CachedStream() {
super();
}
protected void doFlush() throws IOException {
currentStream.flush();
}
protected void doClose() throws IOException {
}
protected void onWrite() throws IOException {
}
}
}
I had this problem as well today. After much weeping and gnashing of teeth, I was able to alter the StreamInterceptor class in the configuration_interceptor demo that comes with the CXF source:
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
String soapMessage = IOUtils.toString(csnew.getInputStream());
...
The soapMessage variable will contain the complete SOAP message. You should be able to manipulate the soap message, flush it to an output stream and do a message.setContent(OutputStream.class... call to put your modifications on the message. This comes with no warranty, since I'm pretty new to CXF myself!
Note: CachedStream is a private class in the StreamInterceptor class. Don't forget to configure your interceptor to run in the PRE_STREAM phase so that the SOAP interceptors have a chance to write the SOAP message.
Following is able to bubble up server side exceptions. Use of os.close() instead of IOUtils.closeQuietly(os) in previous solution is also able to bubble up exceptions.
public class OutInterceptor extends AbstractPhaseInterceptor<Message> {
public OutInterceptor() {
super(Phase.PRE_STREAM);
addBefore(StaxOutInterceptor.class.getName());
}
public void handleMessage(Message message) {
OutputStream os = message.getContent(OutputStream.class);
CachedOutputStream cos = new CachedOutputStream();
message.setContent(OutputStream.class, cos);
message.getInterceptorChain.aad(new PDWSOutMessageChangingInterceptor(os));
}
}
public class OutMessageChangingInterceptor extends AbstractPhaseInterceptor<Message> {
private OutputStream os;
public OutMessageChangingInterceptor(OutputStream os){
super(Phase.PRE_STREAM_ENDING);
addAfter(StaxOutEndingInterceptor.class.getName());
this.os = os;
}
public void handleMessage(Message message) {
try {
CachedOutputStream csnew = (CachedOutputStream) message .getContent(OutputStream.class);
String currentEnvelopeMessage = IOUtils.toString( csnew.getInputStream(), (String) message.get(Message.ENCODING));
csnew.flush();
IOUtils.closeQuietly(csnew);
String res = changeOutboundMessage(currentEnvelopeMessage);
res = res != null ? res : currentEnvelopeMessage;
InputStream replaceInStream = IOUtils.tolnputStream(res, (String) message.get(Message.ENCODING));
IOUtils.copy(replaceInStream, os);
replaceInStream.close();
IOUtils.closeQuietly(replaceInStream);
message.setContent(OutputStream.class, os);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
Good example for replacing outbound soap content based on this
package kz.bee.bip;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
public class SOAPOutboundInterceptor extends AbstractPhaseInterceptor<Message> {
public SOAPOutboundInterceptor() {
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
}
public void handleMessage(Message message) {
boolean isOutbound = false;
isOutbound = message == message.getExchange().getOutMessage()
|| message == message.getExchange().getOutFaultMessage();
if (isOutbound) {
OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
try {
cs.flush();
IOUtils.closeQuietly(cs);
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
String currentEnvelopeMessage = IOUtils.toString(csnew.getInputStream(), "UTF-8");
csnew.flush();
IOUtils.closeQuietly(csnew);
/* here we can set new data instead of currentEnvelopeMessage*/
InputStream replaceInStream = IOUtils.toInputStream(currentEnvelopeMessage, "UTF-8");
IOUtils.copy(replaceInStream, os);
replaceInStream.close();
IOUtils.closeQuietly(replaceInStream);
os.flush();
message.setContent(OutputStream.class, os);
IOUtils.closeQuietly(os);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
public void handleFault(Message message) {
}
private static class CachedStream extends CachedOutputStream {
public CachedStream() {
super();
}
protected void doFlush() throws IOException {
currentStream.flush();
}
protected void doClose() throws IOException {
}
protected void onWrite() throws IOException {
}
}
}
a better way would be to modify the message using the DOM interface, you need to add the SAAJOutInterceptor first (this might have a performance hit for big requests) and then your custom interceptor that is executed in phase USER_PROTOCOL
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Node;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
abstract public class SoapNodeModifierInterceptor extends AbstractSoapInterceptor {
SoapNodeModifierInterceptor() { super(Phase.USER_PROTOCOL); }
#Override public void handleMessage(SoapMessage message) throws Fault {
try {
if (message == null) {
return;
}
SOAPMessage sm = message.getContent(SOAPMessage.class);
if (sm == null) {
throw new RuntimeException("You must add the SAAJOutInterceptor to the chain");
}
modifyNodes(sm.getSOAPBody());
} catch (SOAPException e) {
throw new RuntimeException(e);
}
}
abstract void modifyNodes(Node node);
}
this one's working for me. It's based on StreamInterceptor class from configuration_interceptor example in Apache CXF samples.
It's in Scala instead of Java but the conversion is straightforward.
I tried to add comments to explain what's happening (as far as I understand).
import java.io.OutputStream
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor
import org.apache.cxf.helpers.IOUtils
import org.apache.cxf.io.CachedOutputStream
import org.apache.cxf.message.Message
import org.apache.cxf.phase.AbstractPhaseInterceptor
import org.apache.cxf.phase.Phase
// java note: base constructor call is hidden at the end of class declaration
class StreamInterceptor() extends AbstractPhaseInterceptor[Message](Phase.PRE_STREAM) {
// java note: put this into the constructor after calling super(Phase.PRE_STREAM);
addBefore(classOf[SoapPreProtocolOutInterceptor].getName)
override def handleMessage(message: Message) = {
// get original output stream
val osOrig = message.getContent(classOf[OutputStream])
// our output stream
val osNew = new CachedOutputStream
// replace it with ours
message.setContent(classOf[OutputStream], osNew)
// fills the osNew instead of osOrig
message.getInterceptorChain.doIntercept(message)
// flush before getting content
osNew.flush()
// get filled content
val content = IOUtils.toString(osNew.getInputStream, "UTF-8")
// we got the content, we may close our output stream now
osNew.close()
// modified content
val modifiedContent = content.replace("a-string", "another-string")
// fill original output stream
osOrig.write(modifiedContent.getBytes("UTF-8"))
// flush before set
osOrig.flush()
// replace with original output stream filled with our modified content
message.setContent(classOf[OutputStream], osOrig)
}
}

Vaadin: Downloaded file has whole path as file name

I have a download action implemented on my Vaadin application but for some reason the downloaded file has the original file's full path as the file name.
Any idea?
You can see the code on this post.
Edit:
Here's the important part of the code:
package com.bluecubs.xinco.core.server.vaadin;
import com.bluecubs.xinco.core.server.XincoConfigSingletonServer;
import com.vaadin.Application;
import com.vaadin.terminal.DownloadStream;
import com.vaadin.terminal.FileResource;
import java.io.*;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;
/**
*
* #author Javier A. Ortiz Bultrón<javier.ortiz.78#gmail.com>
*/
public class FileDownloadResource extends FileResource {
private final String fileName;
private File download;
private File newFile;
public FileDownloadResource(File sourceFile, String fileName,
Application application) {
super(sourceFile, application);
this.fileName = fileName;
}
protected void cleanup() {
if (newFile != null && newFile.exists()) {
newFile.delete();
}
if (download != null && download.exists() && download.listFiles().length == 0) {
download.delete();
}
}
#Override
public DownloadStream getStream() {
try {
//Copy file to directory for downloading
InputStream in = new CheckedInputStream(new FileInputStream(getSourceFile()),
new CRC32());
download = new File(XincoConfigSingletonServer.getInstance().FileRepositoryPath
+ System.getProperty("file.separator") + UUID.randomUUID().toString());
newFile = new File(download.getAbsolutePath() + System.getProperty("file.separator") + fileName);
download.mkdirs();
OutputStream out = new FileOutputStream(newFile);
newFile.deleteOnExit();
download.deleteOnExit();
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
final DownloadStream ds = new DownloadStream(
new FileInputStream(newFile), getMIMEType(), fileName);
ds.setParameter("Content-Disposition", "attachment; filename="
+ URLEncoder.encode(fileName, "utf-8"));
ds.setCacheTime(getCacheTime());
return ds;
} catch (final FileNotFoundException ex) {
Logger.getLogger(FileDownloadResource.class.getName()).log(Level.SEVERE, null, ex);
return null;
} catch (IOException ex) {
Logger.getLogger(FileDownloadResource.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
}
I already debugged and verified that fileName only contains the file's name not the whole path.
The answer was actually a mix of houman001's answer and this post: https://vaadin.com/forum/-/message_boards/view_message/200534
I went away from the above approach to a simpler working one:
StreamSource ss = new StreamSource() {
byte[] bytes = //Get the file bytes here
InputStream is = new ByteArrayInputStream(bytes);
#Override
public InputStream getStream() {
return is;
}
};
StreamResource sr = new StreamResource(ss, <file name>, <Application Instance>);
getMainWindow().open(sr, "_blank");
Here is my code that works fine (downloading a blob from database as a file), but it's using a Servlet and OutputStream rather than DownloadStream in your case:
public class TextFileServlet extends HttpServlet
{
public static final String PARAM_BLOB_ID = "id";
private final Logger logger = LoggerFactory.getLogger(TextFileServlet.class);
#Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException
{
Principal userPrincipal = req.getUserPrincipal();
PersistenceManager pm = PMFHolder.get().getPersistenceManager();
Long id = Long.parseLong(req.getParameter(PARAM_BLOB_ID));
MyFile myfile = pm.getObjectById(MyFile.class, id);
if (!userPrincipal.getName().equals(myfile.getUserName()))
{
logger.info("TextFileServlet.doGet - current user: " + userPrincipal + " file owner: " + myfile.getUserName());
return;
}
res.setContentType("application/octet-stream");
res.setHeader("Content-Disposition", "attachment;filename=\"" + myfile.getName() + "\"");
res.getOutputStream().write(myfile.getFile().getBytes());
}
}
I hope it helps you.
StreamResource myResource = createResource(attachmentName);
System.out.println(myResource.getFilename());
if(attachmentName.contains("/"))
attachmentName = attachmentName.substring(attachmentName.lastIndexOf("/"));
if(attachmentName.contains("\\"))
attachmentName = attachmentName.substring(attachmentName.lastIndexOf("\\"));
myResource.setFilename(attachmentName);
FileDownloader fileDownloader = new FileDownloader(myResource);
fileDownloader.extend(downloadButton);

Resources