Archive

Archive for the ‘Code’ Category

CXF Raw SOAP Envelope via Interceptor

November 3rd, 2009 3 comments

CXF SOAPRecently I started using the CXF SOAP library from Apache and was stumped on a simple problem, that being, how to view/modify a raw SOAP envelope. This sounds like a relatively simple task (not too bad when you know how) however it does in fact require some know-how.

The CXF SOAP library gives you access to all parts of the SOAP request and response life-cycle (via HTTP) using CXF Interceptors. The different points in time are referred to as phases and an interceptor can be placed at any one of the defined phases and automatically gain access to the SOAP message object and it’s current state.

For this example I have chosen Phase.RECEIVE which is one of the first phases which is essentially unprocessed by the CXF SOAP stack, which means I have free rain to pre-process the SOAP envelope (if I want to). Particularly handy if you need to maintain backwards compatibility with old SOAP API’s, poorly defined complex SOAP objects, dodgy WSDL definitions or maybe you simply want to view raw SOAP envelope (handy for debugging).

The crux to this problem is manipulating InputStream’s, once an InputStream has been read it is not available, which obviously causes a problem as the rest of the CXF SOAP stack expects it to be available. The solution is to use the CXF provided CachedOutputStream and IOUtils.copy which takes a cache copy of the InputStream making it available for future use :)

Once the Interceptor is implemented all that remains is to add it to the CXF SOAP client pror to usage.

This is an example of gaining access to an incoming client SOAP envelope, the interceptor could quite easily be in the sent phase or even part of the SOAP server implementation…it’s up to you.

package CXFSoap;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.interceptor.Fault;
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 PacketInterceptor extends AbstractPhaseInterceptor<Message>{

	public PacketInterceptor(){
		super(Phase.RECEIVE);
	}

	public void handleMessage(Message message) throws Fault{
		// Get the supplied SOAP envelope in the form of an InputStream
		InputStream inputStream = message.getContent(InputStream.class);

		if (inputStream != null){
			String processedSoapEnv = "";
			// Cache InputStream so it can be read independently
			CachedOutputStream cachedInputStream = new CachedOutputStream();  
			try {
				IOUtils.copy(inputStream,cachedInputStream);
				inputStream.close();
				cachedInputStream.close();
				
				InputStream tmpInputStream = cachedInputStream.getInputStream();
				try{
					String inputBuffer = "";
					int data;
					while((data = tmpInputStream.read()) != -1){
						byte x = (byte)data;
						inputBuffer += (char)x;
					}
					/**
					  * At this point you can choose to reformat the SOAP
					  * envelope or simply view it just make sure you put
 					  * an InputStream back when you done (see below)
 					  * otherwise CXF will complain.
					  */
					processedSoapEnv = fixSoapEnvelope(inputBuffer);
				}
				catch(IOException e){
					
				}
			} 
			catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			// Re-set the SOAP InputStream with the new envelope
			message.setContent(InputStream.class,new ByteArrayInputStream(processSoapEnv.getBytes()));
	
			/**		
			 * If you just want to read the InputStream and not 
			 * modify it then you just need to put it back where
			 * it was using the CXF cached inputstream
			 *
			 * message.setContent(InputStream.class,cachedInputStream.getInputStream());
			*/
		}
	}

	private String fixSoapEnvelope(String xml){
		...
	}
}

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import Stuff.StuffObj;
import CXFSoap.PacketInterceptor;
import CXFSoap.VIPCoreAPI;

public class CXFTest{

	    public static void main(String args[]) throws Exception{
	    		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		    	factory.setServiceClass(VIPCoreAPI.class);
		    	factory.setAddress("http://x.x.x.x/SOAP/API");
		    	factory.setWsdlLocation("http://x.x.x.x/SOAP/API?wsdl");
		    	factory.setUsername("xxx");
		    	factory.setPassword("xxx");


		    	/**
		    	 * This is the important part, the interceptor needs
		    	 * to be added to the CXF SOAP client prior to
		    	 * the SOAP call being made.
		    	 */
		    	factory.getInInterceptors().add(new PacketInterceptor());

		    	API client = (API)factory.create();
		    	StuffObj stuff = client.getStuff();
		    	System.out.print(stuff.toString());
	    }
}

SOAP Debugging with tcpdump

October 27th, 2009 No comments

You are on a Linux box (SOAP client) making a SOAP request to a SOAP server somewhere on port 80, to view the request and response with tcpdump here are the commands execute at shell.

Incoming SOAP envelope (server response)

tcpdump  -nnvvlXSs 4096 src port 80

Outgoing SOAP envelope (client request)

tcpdump  -nnvvlXSs 4096 dst port 80

Of course if you have additional traffic going in and out from this box you can use the “and” operator to fine tune what you are after.

Categories: General, Linux, Web/HTML Tags: ,

Java: File Copy and File Move

October 7th, 2009 No comments

It has been a while since I’ve done any major Java development, it seems I have got used to having all the standard file tools which are available in scripted 4th and 5th generation languages like PHP.

Java whilst incredibly powerful is sometimes a bit awkward when dealing with certain problems. Often it’s the level abstraction and/or ability to get under the hood that can cloud a somewhat simple task, in my case file copying and moving.

Here is a small package that simplifies file copies and moves :)

package Utils.SystemTools;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FileCopy{
	
	public static void copy(File source,File dest) throws IOException{
		try{
			copy(source.getPath(),dest.getPath());
		} 
		catch (IOException e){
			throw e;
		}
	}
	
	public static void copy(String source,String dest) throws IOException{
		try{
			File sourceFile = new File(source);
			File destFile = new File(dest);
			InputStream in = new FileInputStream(sourceFile);
			OutputStream out = new FileOutputStream(destFile);
			
			int bufferSize = 1024;
			byte[] buf = new byte[bufferSize];
			int len;
			while ((len = in.read(buf)) > 0){
				out.write(buf,0,len);
			}
			in.close();
			out.close();
	    }
	    catch(IOException e){
	    	throw e;
	    }
	}
	
	public static void move(String source,String dest) throws IOException{
		try{
			copy(source,dest);
		}
		catch(IOException e){
			throw e;
		}
		File sourceFile = new File(source);
		if (!sourceFile.delete()){
			throw new IOException("File deletion failed for: " + source);
		}
	}

	public static void move(File source,File dest) throws IOException{
		try{
			move(source.getPath(),dest.getPath());
		}
		catch(IOException e){
			throw e;
		}
		if (!source.delete()){
			throw new IOException("File deletion failed for: " + source.getPath());
		}
	}	
	
}
Categories: Code, General, Java Tags: ,

Flex: Multiple File Uploader

October 1st, 2009 13 comments

Flex Multi UploaderUploading is such a common task and can often be a little painful so I decided to write a small library in Flex which simplifies the task. I have released it under GPL license so feel free to use and modify it according to the conditions :)

The Flex client side uploader supports multiple file upload with queuing and multiple threads, meaning more than one upload can be active at a time. It is also written in component style so creating an instance of the uploader is very simple and can be achieved in only a few lines of code (see the example below). It also supports posted additional data with the file upload, handy if you need to pass instructions to the back-end upload script.

The back-end script is not included in the library but could easily be implemented in any language. I have however supplied a PHP example below of how to implement the back-end script to support the Flex uploader (see the example below).

One final note, this code is not polished, it’s definitely Alpha…but still very usable. If you have any issues or questions please let me know, cheers.

Simple example implementation of uploader library

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
				xmlns:cc="FileUploader.Renderers.*" 
				layout="absolute"
			    creationComplete="{init()}"
			    width="1018"
			    height="455"
				>
	<mx:Script>
		<![CDATA[
			
			private function init():void{
				fileUploader.addPostData('mydata','1234567890');
			}
			
		]]>
	</mx:Script>
				
	<cc:FileUploadComp id="fileUploader"
					   x="0"
					   top="8"
					   left="8"
					   width="1000"
					   maxThreadsEnabled="true"
					   uploadUrl="http://a.b.c.d/MyUploaderScript.php"
					   />
</mx:Application>


PHP backend example implementation of uploader code

<?php
	$tmpFileName = isset($_FILES['Filedata']['tmp_name']) ? $_FILES['Filedata']['tmp_name'] : '';
	$orgFileName = isset($_FILES['Filedata']['name']) ? $_FILES['Filedata']['name'] : '';
	$mydata = isset($_REQUEST['mydata']) ? $_REQUEST['mydata'] : '';
	
	error_log('tmpfile: ' . $tmpFileName);
	error_log('filename: ' . $orgFileName);
	error_log('mydata: ' . $mydata);	

	if (true){
		print 'ok'; 
	}
	else{
		header('Status: 500 ' . $resultAry[1]);
		header('HTTP/1.1 500 ' . $resultAry[1]);
		
		$outputStr = '<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">' .
				 '<html><head>' .
				 '<title>500 ' . $resultAry[1] . '</title>' .
				 '</head><body>' .
				 '<h1>500 ' . $resultAry[1] . '</h1>' . 
				 '<hr>' .
				 $_SERVER['SERVER_SIGNATURE'] .
				 '</body></html>';
		print $outputStr;
	}
?>

Also here’s and example of a Flash crossdomain.xml (this one is reasonably open!) which will be needed in the root of your site…otherwise flex will complain.

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<allow-access-from domain="*" to-ports="*"/>
	<site-control permitted-cross-domain-policies="all"/>
</cross-domain-policy>

Demo Flex Uploader

DOWNLOAD (version 1.0a)

Simple Java File Logging

September 30th, 2009 No comments

Not much to say about this one, a small one off independent class to simplify the process of logging stuff to file. Something like this is often handy when writing backgrounded daemon processes.

FileLogger class

package Utils;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FileLogger{
	
	private File logFile;
	
	private long logEntryNo = 0;
	
	private static FileLogger instance = null;
	
	public static final String DEFAULT_LOG_FILEPATH = "bin/Log/Daemon.log";
	
	public FileLogger(String logFilePath){
		logFile = new File(logFilePath);
		try{
			logFile.createNewFile();
		} 
		catch (IOException e) {
			e.printStackTrace();
		}
		calcNumLines();
		instance = this;
	}
	
	public FileLogger(File logFile){
		this.logFile = logFile;
		calcNumLines();
		instance = this;
	}
	
	public static FileLogger getInstance(){
		return instance;
	}

	/**
	 * Adds and entry in the log file but also echos the log to standard out
	 * 
	 * @param data
	 * @param printToStdOut
	 */
	
	public void add(String data,boolean printToStdOut){
		if (printToStdOut){
			System.out.print("\n" + data + "\n");
		}
		add(data);
	}
	
	/**
	 * Add a log file entry
	 * 
	 * @param data
	 */
	
	public synchronized void add(String data){
		DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
		Date date = new Date();
		String dateTime = dateFormat.format(date);
		
		try{
			if (logFile.createNewFile()){
				FileWriter fileWriter = new FileWriter(logFile);
				BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
				bufferedWriter.write("[" + dateTime +  "]#" + ++logEntryNo + ": " + data);
				bufferedWriter.newLine();
				bufferedWriter.close();
			}
			else{
				FileWriter fileWriter = new FileWriter(logFile,true);
				BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
				bufferedWriter.write("[" + dateTime +  "]#" + ++logEntryNo + ": " + data);
				bufferedWriter.newLine();
				bufferedWriter.close();
			}
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void calcNumEntries(){
		try {
			FileReader fileReader = new FileReader(logFile);
			BufferedReader bufferedFileReader = new BufferedReader(fileReader);
			
			try{
				String line;
				while((line = bufferedFileReader.readLine()) != null){
					Pattern p = Pattern.compile("^\\[\\d+\\.\\d+\\.\\d+\\s+\\d+:\\d+:\\d+]#\\d+");
					Matcher m = p.matcher(line);
					
					if (m.find()){
						logEntryNo++;
					}
				}
				bufferedFileReader.close();
			} 
			catch (IOException e){
				e.printStackTrace();
			}
		} 
		catch (FileNotFoundException e){
			// The log file hasn't been created yet so gracefully ignore that fact
		}
	}
	
}

Usage:

FileLogger myFileLogger = new FileLogger(FileLogger.DEFAULT_LOG_FILEPATH);
myFileLogger.add("my log entry");