Handling embedded images in IText XMLWorker - image

Handling embedded images in IText XMLWorker.
Is there a way to handle Embedded (Base64) images in XMLWorker? In version 5.3.5
the ImageProvider I used does not work any more (an exception is raised before),
so I Patched ImageRetrieve as follows, but obviously this will be broken in next
XMLWorker update:
package com.itextpdf.tool.xml.net;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.codec.Base64;
import com.itextpdf.tool.xml.net.exc.NoImageException;
import com.itextpdf.tool.xml.pipeline.html.ImageProvider;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* #author redlab_b
*
*/
public class ImageRetrieve {
final static Pattern INLINE_PATTERN = Pattern.compile("^/data:image/(png|jpg|gif);base64,(.*)");
private final ImageProvider provider;
/**
* #param imageProvider the provider to use.
*
*/
public ImageRetrieve(final ImageProvider imageProvider) {
this.provider = imageProvider;
}
/**
*
*/
public ImageRetrieve() {
this.provider = null;
}
/**
* #param src an URI that can be used to retrieve an image
* #return an iText Image object
* #throws NoImageException if there is no image
* #throws IOException if an IOException occurred
*/
public com.itextpdf.text.Image retrieveImage(final String src) throws NoImageException, IOException {
com.itextpdf.text.Image img = null;
if (null != provider) {
img = provider.retrieve(src);
}
if (null == img) {
String path = null;
if (src.startsWith("http")) {
// full url available
path = src;
} else if (null != provider){
String root = this.provider.getImageRootPath();
if (null != root) {
if (root.endsWith("/") && src.startsWith("/")) {
root = root.substring(0, root.length() - 1);
}
path = root + src;
}
} else {
path = src;
}
if (null != path) {
try {
Matcher m;
if (path.startsWith("http")) {
img = com.itextpdf.text.Image.getInstance(path);
} else if ((m = INLINE_PATTERN.matcher(path)).matches()) {
// Let's handle the embedded image without saving it
try {
byte[] data = Base64.decode(m.group(2));
return Image.getInstance(data);
} catch (Exception ex) {
throw new NoImageException(src, ex);
}
} else {
img = com.itextpdf.text.Image.getInstance(new File(path).toURI().toURL());
}
if (null != provider && null != img) {
provider.store( src, img);
}
} catch (BadElementException e) {
throw new NoImageException(src, e);
} catch (MalformedURLException e) {
throw new NoImageException(src, e);
}
} else {
throw new NoImageException(src);
}
}
return img;
}
}

It's almost year since you asked this question, but maybe this answer will help anyway.
Recently I met similar problem. My goal was to include in generated pdf an image stored in database.
To do this I've extended the com.itextpdf.tool.xml.pipeline.html.AbstractImageProvider class and overriden its retrieve() method like this:
public class MyImageProvider extends AbstractImageProvider {
#Override
public Image retrieve(final String src) {
Image img = super.retrieve(src);
if (img == null) {
try {
byte [] data = getMyImageSomehow(src);
img = Image.getInstance(data);
super.store(src, img);
}
catch (Exception e) {
//handle exceptions
}
}
return img;
}
#Override
public String getImageRootPath() {
return "http://sampleurl/img";
}
}
Then, when building pipelines for XMLWorker [1], I pass an instance of my class to context:
htmlPipelineContext.setImageProvider(new MyImageProvider());
Now we would expect that this should work. But there's a catch! Somewhere, deep inside the xmlworker library, this htmlPipelineContext is being cloned. And during this operation our implementation of ImageProvider get's lost. This is happening inside HtmlPipelineContext's clone() method. Take a look at lines 274-280 (I refer to 5.4.4 version):
final String rootPath = imageProvider.getImageRootPath();
newCtx.setImageProvider(new AbstractImageProvider() {
public String getImageRootPath() {
return rootPath;
}
});
This is even described in HtmlPipelineContext.clone()'s javadoc [2]:
Create a clone of this HtmlPipelineContext, the clone only contains the initial values, not the internal values. Beware, the state of the current Context is not copied to the clone. Only the configurational important stuff like the (...) ImageProvider (new AbstractImageProvider with same ImageRootPath) , (...) are copied.
Isn't it funny? You get class that is designed for extending by making it abstract, but at the end it turns out, that this class serves only as a property holder.
My workaround for this:
public class MySpecialImageProviderAwareHtmlPipelineContext extends HtmlPipelineContext {
MySpecialImageProviderAwareHtmlPipelineContext () {
super(null);
}
public HtmlPipelineContext clone () {
HtmlPipelineContext ctx = null;
try {
ctx = super.clone();
ctx.setImageProvider(new MyImageProvider());
} catch (Exception e) {
//handle exception
}
return ctx;
}
}
Then I just use this instead of HtmlPipelineContext.
[1] http://demo.itextsupport.com/xmlworker/itextdoc/flatsite.html#itextdoc-menu-7
[2] http://api.itextpdf.com/xml/com/itextpdf/tool/xml/pipeline/html/HtmlPipelineContext.html#clone()

And hopefully, your solution seems to have been adopted in later version (5.5.6 at least).

Related

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

Bukkit - How to reload custom yaml-configuration

Okay, so I'm trying to make a toggleable feature, whether they have it enabled/disabled is stored in the 'data.yml'. The issue I have with this is that the file does get updated (Asin, it does change from true to false and vice versa) but it doesn't actually apply the changes in-game.
Method for reloading the file:
public static void reloadConfig(File file, FileConfiguration conf) {
try {
conf.save(file);
} catch (Exception e) {
}
conf = YamlConfiguration.loadConfiguration(file);
}
Toggle command:
if (args[0].equalsIgnoreCase("toggle")) {
File file = new File("plugins/StatTrack", "data.yml");
if (file.exists()) {
FileConfiguration conf = YamlConfiguration.loadConfiguration(file);
if (conf.getBoolean("Users." + player.getName() + ".OreTracker") == true) {
conf.set("Users." + player.getName() + ".OreTracker", false);
try {
Main.reloadConfig(file, conf);
Main.message(player, "&cDisabled&f the Ore&8-&fTracker");
return true;
} catch (Exception e) {
Main.message(player, "&cSome fatal error occored");
return true;
}
} else if (conf.getBoolean("Users." + player.getName() + ".OreTracker") == false) {
conf.set("Users." + player.getName() + ".OreTracker", true);
try {
Main.reloadConfig(file, conf);
Main.message(player, "&aEnabled&f the Ore&8-&fTracker");
return true;
} catch (Exception e) {
Main.message(player, "&cSome fatal error occored");
return true;
}
}
}
}
If you need any more code or have any questions I'll happily supply the code/answer.
Thanks in advance.
The problem is that the plugin is saving the config in the reload method. I also wouldn't recommend using a static method in this case unless the class of the method is a Singleton.
So let's create a new class being a Singleton. The Singleton pattern describes a class which has only one instance accessible through static methods.
public class PluginConfig {
private static PluginConfig instance; // Static (global) reference to the instance
File confFile;
YamlConfiguration conf;
public PluginConfig(File confFile) {
this.confFile = confFile;
loadConfig();
}
public static YamlConfiguration getConfig() {
return instance.conf;
}
public static void loadConfig() {
instance.conf = YamlConfiguration.loadConfiguration(confFile);
}
// Extra method for another implementation, if potentially needed in the future
public static void reloadConfig() {
loadConfig();
}
}
Using that class you can access the config from everywhere with PluginConfig.getConfig()

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)
}
}

How to display a clob data more than 66k in text field in oracle forms 12g

I don't know how to put clob data which is of more than 66k in Oracle Forms.
The text field will take a long data type and that too not more than 66k. I have a clob data and wanted to display.
The easiest way to display this is too make a forms bean (PJC).
Then you can display it in a JTextPane which is big enough.
You can then make a function that gives you piece of 32000 characters from the clob and give them to the bean.
package be.axi.oracle.forms.jpc;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.text.BadLocationException;
import oracle.forms.handler.IHandler;
import oracle.forms.properties.ID;
import oracle.forms.ui.CustomEvent;
import oracle.forms.ui.VBean;
/**
* A TextArea to get more than 64k texts
* #author Francois Degrelle
* #version 1.1
*/
public class BigTextArea extends VBean implements FocusListener, KeyListener
{
private static final long serialVersionUID = 1L;
public final static ID ADDTEXT = ID.registerProperty("ADD_TEXT");
public final static ID VALUE = ID.registerProperty("VALUE");
public final static ID SHOW = ID.registerProperty("SHOW");
public final static ID CLEAR = ID.registerProperty("CLEAR");
public final static ID GETTEXT = ID.registerProperty("GET_TEXT");
public final static ID GETLENGTH = ID.registerProperty("GET_LENGTH");
public final static ID pLostFocus = ID.registerProperty("BEAN_QUITTED");
private IHandler m_handler;
private int iStart = 0 ;
private int iChunk = 8192 ;
private StringBuffer sb = new StringBuffer();
protected JTextPane jtp = new JTextPane();
public BigTextArea()
{
super();
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.updateComponentTreeUI(this);
}
catch (Exception ex)
{
ex.printStackTrace();
}
JScrollPane ps = new JScrollPane(jtp);
ps.setBorder(null);
add(ps);
ps.setVisible(true);
}
public void init(IHandler handler)
{
m_handler = handler;
super.init(handler);
addFocusListener(this);
jtp.addFocusListener(this);
jtp.addKeyListener(this);
}
public boolean setProperty(ID property, Object value)
{
//
// add text to the TextArea
//
if (property == ADDTEXT)
{
sb.append(value.toString()) ;
printMemory();
return true;
}
//
// display the whole text
//
else if(property == SHOW)
{
jtp.setText(sb.toString());
jtp.setCaretPosition(0);
sb = new StringBuffer();
System.gc();
printMemory();
return true ;
}
//
// clear the TextArea
//
else if(property == CLEAR) {
jtp.setText("");
return true ;
}
else
{
return super.setProperty(property, value);
}
}
/*-----------------------------------*
* Get the result string from Forms *
*-----------------------------------*/
public Object getProperty(ID pId)
{
//
// returns the text length
//
if (pId == GETLENGTH)
{
return "" + jtp.getText().length();
}
//
// returns the chunks
//
else if (pId == GETTEXT) {
String s = "" ;
int iLen = jtp.getText().length() ;
while (iStart < iLen)
{
try{
if(iStart+iChunk <= iLen) s = jtp.getText(iStart,iChunk);
else s = jtp.getText(iStart,iLen-iStart);
iStart += iChunk ;
return s ;
}
catch (BadLocationException ble) { ble.printStackTrace(); return ""; }
}
iStart = 0 ;
return "" ;
}
else
{
return super.getProperty(pId);
}
} // getProperty()
/*--------------------------*
* handle the focus events *
*--------------------------*/
public void focusGained(FocusEvent e)
{
if (e.getComponent() == this)
{
// put the focus on the component
jtp.requestFocus();
}
try
{
m_handler.setProperty(FOCUS_EVENT, e);
}
catch ( Exception ex )
{
;
}
}
public void focusLost(FocusEvent e)
{
CustomEvent ce = new CustomEvent(m_handler, pLostFocus);
dispatchCustomEvent(ce);
}
/*--------------------------*
* Handle the Key listener *
*--------------------------*/
public void keyPressed(KeyEvent e)
{
/*
** Allows TAB key to exit the item
** and continue the standard Forms navigation
*/
if ( (e.getKeyCode() == KeyEvent.VK_TAB) )
{
try
{
m_handler.setProperty(KEY_EVENT, e);
}
catch ( Exception ex )
{
}
}
}
public void keyTyped(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
}
// utility to output the memory available
private void printMemory() {
System.out.println("Java memory in use = "
+ (Runtime.getRuntime().totalMemory()
- Runtime.getRuntime().freeMemory()));
}
}

Quartz doesn't recognize schema job_scheduling_data_2_0.xsd present in quartz jar file

I am getting below exception on server startup.
I am using quartz 2.2.21 with spring 3.2.
I have enabled quartz plugin (org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin).
Please find below the start tag of our XML file:
During server startup we are getting below log information and stacktrace:
Error Message:
Unable to load local schema packaged in quartz distribution jar. Utilizing schema online at http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd
Exception:
Caused by: org.xml.sax.SAXParseException; systemId: file:///quartz_job_data.xml; lineNumber: 5; columnNumber: 104;
schema_reference.4: Failed to read schema document 'http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
I have the same problem. I'm using the 7.1.1 of Jboss and the problem appears when you don't have connection to the internet. This is easy as putting a fake address that's unreachable in hosts.
I tried to force to local copy but it does not work.
What I finally did is to partially overwrite the functionality until this is fixed. Watch: https://jira.spring.io/browse/SPR-13706
public class CustomXMLSchedulingDataProcessor extends org.quartz.xml.XMLSchedulingDataProcessor {
public static final String QUARTZ_XSD_PATH_IN_JAR_CLASSPATH = "classpath:org/quartz/xml/job_scheduling_data_2_0.xsd";
public CustomXMLSchedulingDataProcessor(ClassLoadHelper clh) throws ParserConfigurationException {
super(clh);
}
#Override
protected Object resolveSchemaSource() {
InputSource inputSource;
InputStream is = null;
try {
is = classLoadHelper.getResourceAsStream(QUARTZ_XSD_PATH_IN_JAR_CLASSPATH);
} finally {
if (is != null) {
inputSource = new InputSource(is);
inputSource.setSystemId(QUARTZ_SCHEMA_WEB_URL);
}
else {
return QUARTZ_SCHEMA_WEB_URL;
}
}
return inputSource;
}
}
And I did a new plugin XMLSchedulingDataProcessorPlugin overwritting just the instanciation of above class.
public class XMLSchedulingDataProcessorPlugin
extends SchedulerPluginWithUserTransactionSupport
implements FileScanListener {
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Data members.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
private static final int MAX_JOB_TRIGGER_NAME_LEN = 80;
private static final String JOB_INITIALIZATION_PLUGIN_NAME = "JobSchedulingDataLoaderPlugin";
private static final String FILE_NAME_DELIMITERS = ",";
private boolean failOnFileNotFound = true;
private String fileNames = CustomXMLSchedulingDataProcessor.QUARTZ_XML_DEFAULT_FILE_NAME;
// Populated by initialization
private Map<String, JobFile> jobFiles = new LinkedHashMap<String, JobFile>();
private long scanInterval = 0;
boolean started = false;
protected ClassLoadHelper classLoadHelper = null;
private Set<String> jobTriggerNameSet = new HashSet<String>();
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Constructors.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
public XMLSchedulingDataProcessorPlugin() {
}
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* Comma separated list of file names (with paths) to the XML files that should be read.
*/
public String getFileNames() {
return fileNames;
}
/**
* The file name (and path) to the XML file that should be read.
*/
public void setFileNames(String fileNames) {
this.fileNames = fileNames;
}
/**
* The interval (in seconds) at which to scan for changes to the file.
* If the file has been changed, it is re-loaded and parsed. The default
* value for the interval is 0, which disables scanning.
*
* #return Returns the scanInterval.
*/
public long getScanInterval() {
return scanInterval / 1000;
}
/**
* The interval (in seconds) at which to scan for changes to the file.
* If the file has been changed, it is re-loaded and parsed. The default
* value for the interval is 0, which disables scanning.
*
* #param scanInterval The scanInterval to set.
*/
public void setScanInterval(long scanInterval) {
this.scanInterval = scanInterval * 1000;
}
/**
* Whether or not initialization of the plugin should fail (throw an
* exception) if the file cannot be found. Default is <code>true</code>.
*/
public boolean isFailOnFileNotFound() {
return failOnFileNotFound;
}
/**
* Whether or not initialization of the plugin should fail (throw an
* exception) if the file cannot be found. Default is <code>true</code>.
*/
public void setFailOnFileNotFound(boolean failOnFileNotFound) {
this.failOnFileNotFound = failOnFileNotFound;
}
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* SchedulerPlugin Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* <p>
* Called during creation of the <code>Scheduler</code> in order to give
* the <code>SchedulerPlugin</code> a chance to initialize.
* </p>
*
* #throws org.quartz.SchedulerConfigException
* if there is an error initializing.
*/
public void initialize(String name, final Scheduler scheduler, ClassLoadHelper schedulerFactoryClassLoadHelper)
throws SchedulerException {
super.initialize(name, scheduler);
this.classLoadHelper = schedulerFactoryClassLoadHelper;
getLog().info("Registering Quartz Job Initialization Plug-in.");
// Create JobFile objects
StringTokenizer stok = new StringTokenizer(fileNames, FILE_NAME_DELIMITERS);
while (stok.hasMoreTokens()) {
final String fileName = stok.nextToken();
final JobFile jobFile = new JobFile(fileName);
jobFiles.put(fileName, jobFile);
}
}
#Override
public void start(UserTransaction userTransaction) {
try {
if (jobFiles.isEmpty() == false) {
if (scanInterval > 0) {
getScheduler().getContext().put(JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName(), this);
}
Iterator<JobFile> iterator = jobFiles.values().iterator();
while (iterator.hasNext()) {
JobFile jobFile = iterator.next();
if (scanInterval > 0) {
String jobTriggerName = buildJobTriggerName(jobFile.getFileBasename());
TriggerKey tKey = new TriggerKey(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME);
// remove pre-existing job/trigger, if any
getScheduler().unscheduleJob(tKey);
JobDetail job = newJob().withIdentity(jobTriggerName, JOB_INITIALIZATION_PLUGIN_NAME).ofType(FileScanJob.class)
.usingJobData(FileScanJob.FILE_NAME, jobFile.getFileName())
.usingJobData(FileScanJob.FILE_SCAN_LISTENER_NAME, JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName())
.build();
SimpleTrigger trig = newTrigger().withIdentity(tKey).withSchedule(
simpleSchedule().repeatForever().withIntervalInMilliseconds(scanInterval))
.forJob(job)
.build();
getScheduler().scheduleJob(job, trig);
getLog().debug("Scheduled file scan job for data file: {}, at interval: {}", jobFile.getFileName(), scanInterval);
}
processFile(jobFile);
}
}
} catch(SchedulerException se) {
getLog().error("Error starting background-task for watching jobs file.", se);
} finally {
started = true;
}
}
/**
* Helper method for generating unique job/trigger name for the
* file scanning jobs (one per FileJob). The unique names are saved
* in jobTriggerNameSet.
*/
private String buildJobTriggerName(
String fileBasename) {
// Name w/o collisions will be prefix + _ + filename (with '.' of filename replaced with '_')
// For example: JobInitializationPlugin_jobInitializer_myjobs_xml
String jobTriggerName = JOB_INITIALIZATION_PLUGIN_NAME + '_' + getName() + '_' + fileBasename.replace('.', '_');
// If name is too long (DB column is 80 chars), then truncate to max length
if (jobTriggerName.length() > MAX_JOB_TRIGGER_NAME_LEN) {
jobTriggerName = jobTriggerName.substring(0, MAX_JOB_TRIGGER_NAME_LEN);
}
// Make sure this name is unique in case the same file name under different
// directories is being checked, or had a naming collision due to length truncation.
// If there is a conflict, keep incrementing a _# suffix on the name (being sure
// not to get too long), until we find a unique name.
int currentIndex = 1;
while (jobTriggerNameSet.add(jobTriggerName) == false) {
// If not our first time through, then strip off old numeric suffix
if (currentIndex > 1) {
jobTriggerName = jobTriggerName.substring(0, jobTriggerName.lastIndexOf('_'));
}
String numericSuffix = "_" + currentIndex++;
// If the numeric suffix would make the name too long, then make room for it.
if (jobTriggerName.length() > (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length())) {
jobTriggerName = jobTriggerName.substring(0, (MAX_JOB_TRIGGER_NAME_LEN - numericSuffix.length()));
}
jobTriggerName += numericSuffix;
}
return jobTriggerName;
}
/**
* Overriden to ignore <em>wrapInUserTransaction</em> because shutdown()
* does not interact with the <code>Scheduler</code>.
*/
#Override
public void shutdown() {
// Since we have nothing to do, override base shutdown so don't
// get extranious UserTransactions.
}
private void processFile(JobFile jobFile) {
if (jobFile == null || !jobFile.getFileFound()) {
return;
}
try {
CustomXMLSchedulingDataProcessor processor =
new CustomXMLSchedulingDataProcessor(this.classLoadHelper);
processor.addJobGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME);
processor.addTriggerGroupToNeverDelete(JOB_INITIALIZATION_PLUGIN_NAME);
processor.processFileAndScheduleJobs(
jobFile.getFileName(),
jobFile.getFileName(), // systemId
getScheduler());
} catch (Exception e) {
getLog().error("Error scheduling jobs: " + e.getMessage(), e);
}
}
public void processFile(String filePath) {
processFile((JobFile)jobFiles.get(filePath));
}
/**
* #see org.quartz.jobs.FileScanListener#fileUpdated(java.lang.String)
*/
public void fileUpdated(String fileName) {
if (started) {
processFile(fileName);
}
}
class JobFile {
private String fileName;
// These are set by initialize()
private String filePath;
private String fileBasename;
private boolean fileFound;
protected JobFile(String fileName) throws SchedulerException {
this.fileName = fileName;
initialize();
}
protected String getFileName() {
return fileName;
}
protected boolean getFileFound() {
return fileFound;
}
protected String getFilePath() {
return filePath;
}
protected String getFileBasename() {
return fileBasename;
}
private void initialize() throws SchedulerException {
InputStream f = null;
try {
String furl = null;
File file = new File(getFileName()); // files in filesystem
if (!file.exists()) {
URL url = classLoadHelper.getResource(getFileName());
if(url != null) {
try {
furl = URLDecoder.decode(url.getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
furl = url.getPath();
}
file = new File(furl);
try {
f = url.openStream();
} catch (IOException ignor) {
// Swallow the exception
}
}
} else {
try {
f = new java.io.FileInputStream(file);
}catch (FileNotFoundException e) {
// ignore
}
}
if (f == null) {
if (isFailOnFileNotFound()) {
throw new SchedulerException(
"File named '" + getFileName() + "' does not exist.");
} else {
getLog().warn("File named '" + getFileName() + "' does not exist.");
}
} else {
fileFound = true;
}
filePath = (furl != null) ? furl : file.getAbsolutePath();
fileBasename = file.getName();
} finally {
try {
if (f != null) {
f.close();
}
} catch (IOException ioe) {
getLog().warn("Error closing jobs file " + getFileName(), ioe);
}
}
}
}
}
That way you only have to use this plugin in your configuration and everything will work by default.
org.quartz.plugin.jobInitializer.class =
com.level2.quartz.processor.plugin.XMLSchedulingDataProcessorPlugin

Resources