Code I/O

A topnotch WordPress.com site


Leave a comment

5 minutes on Adobe Flex: A service proxy pattern for applications

The process of communication involved between Rich Internet Applications and Server components is very repeatable:

  • Sending request to server
  • handling its result or fault, and
  • finally processing the result for the application to provide desired functionality

The process involves invoking services and handling responses individually, One can think of simplifying the process by introducing the Service Proxy pattern, which becomes handy to manage the entire application specific communications.

The benefit of this pattern is that, one can process results specifically with respect to business logic at the same time having a unified interface to manage server side interactions.

package service
{
 import mx.controls.Alert;
 import mx.rpc.events.FaultEvent;
 import mx.rpc.events.ResultEvent;
 import mx.rpc.http.HTTPService;

 public class ServiceProxy
 {
 private static var SERVICE_URL:String;
 public static function getURL():String{
 return SERVICE_URL;
 }
 public static const TERMS_AND_CONDITIONS_PAGE:String = "/sub_tac.html";

 public function ServiceProxy()
 {
 throw new Error("ServiceProxy cannot be instantiated");
 }

 public static const CHECK_SUBSCRIBER:String     = "CHECK_SUBSCRIBER";
 public static const LOAD_DICTIONARY:String         = "LOAD_DICTIONARY";
 public static const SUBSCRIBE:String             = "SUBSCRIBE";
 public static const UNSUBSCRIBE:String             = "UNSUBSCRIBE";
 public static const CHANGE_SUBSCRIPTIONS:String = "CHANGE_SUBSCRIPTIONS";

 private static function init():void {
 register(LOAD_DICTIONARY,
 {script:"/php/load_dictionary.php",         method:"GET",    success:"", failure:""});

 register(CHANGE_SUBSCRIPTIONS,
 {script:"/php/change_subscriptions.php",     method:"POST",    success:"/sub_success.html", failure:""});

 register(CHECK_SUBSCRIBER,
 {script:"/php/check_subscriber.php",         method:"POST",    success:"", failure:""});

 register(SUBSCRIBE,
 {script:"/php/subscribe.php",                 method:"POST",     success:"/sub_success.html", failure:""});

 register(UNSUBSCRIBE,
 {script:"/php/unsubscribe.php",             method:"POST",    success:"/unsub_success.html", failure:""});
 }

 private static var registry:Object = null;
 public static function getObjectByTag(tag:String):Object{
 if(registry == null){
 registry = {};

 init();
 }

 return registry[tag];
 }

 public static function register(handle:String, object:Object):Boolean {
 if(!registry[handle]){
 registry[handle] = object;
 return true;
 }

 return false;
 }

 public static function execute(tag:String, xml:XML=null, callback:Function=null):void {
 var o:Object = getObjectByTag(tag);
 if(o == null){
 throw new Error(tag + " is not supported currently!!");
 return;
 }

 var s:HTTPService = new HTTPService();

 s.url = SERVICE_URL + o.script;
 s.method = o.method;
 s.contentType = HTTPService.CONTENT_TYPE_XML;
 s.resultFormat = HTTPService.RESULT_FORMAT_E4X;

 if(xml != null){
 s.request = xml;
 }

 s.addEventListener(ResultEvent.RESULT,
 function resultHandler(event:ResultEvent):void
 {
 var xml:XML = XML(event.result);

 trace("RESULTn" + xml);
 if(callback != null){
 callback(xml);
 }
 }
 );

 s.addEventListener(FaultEvent.FAULT,
 function faultHandler(event:FaultEvent):void
 {
 trace("ERROR: " + event.message);
 Alert.show("Error communicating to server, try again later", "Communication Fault");
 }
 );

 s.send();
 }

 public static function initFromURL():void
 {
 var url:String = FlexGlobals.topLevelApplication.url;
 var protocol:String = "http";
 var server:String = "192.168.1.100";
 var port:String = "8085";
 var prefix:String = "/referral-network";

 if (url.search("file://") >= 0)
 {
 }
 else
 {
 var i:int = url.indexOf("://");
 if (i >= 0) {
 protocol = url.substring(0, i);
 }

 url = url.replace(protocol + "://", "");
 url = url.substring(0, url.search("/"));

 var array:Array = url.split(":");
 if (array.length >= 1)
 {
 server = array[0];
 }
 if (array.length >= 2)
 {
 port = array[1];
 }
 else
 {
 if (protocol != null && protocol == "https")
 port = "443";
 else
 port = "80";
 }
 }

 SERVICE_URL = protocol + "://" + server + ":" + port + prefix;
 }
 }
}

Here is a simple usage of the pattern

public function unSubscribe():void{
	var xml:XML = <input />;

	var profile:XML = <profile />;
	xml.appendChild(profile);

	trace("DATA TO SEND: " + xml);
	ServiceProxy.execute(ServiceProxy.UNSUBSCRIBE, xml, unsubscribeResultHandler);
}

private function unsubscribeResultHandler(xml:XML):void{
	// Your Business Logic Here ...
}
Advertisements


1 Comment

5 Minutes on Adobe Flex: Mimic file upload for in-memory contents …

Ever imagined uploading a file without using FileReference.upload?

In a web-app, access to filesystem is restricted, and at times, there is no need to refer to a file.  However, there may be situation where there is need to persist in-memory contents on servers.

The idea is to send contents from internal buffer which are non-file reference objects.  The fundamental behind  this is to fill in the content headers and mimic fileupload using HTTPService and here is the snippet for spoofing it.

Remember, though one can spoof the file upload, the trigger must be coming from an UI object (like a Button click event), otherwise, Flash will fail to upload the content.

public function spoofFileUpload(inputText:String,
 fileName:String,
 resultHandler:Function,
 faultHander:Function=null):void {

 var boundary:String = UIDUtil.createUID();
 var service:HTTPService = new HTTPService();

 service.url = SOME_SERVER_URI_ACCEPTING_FILE;
 service.method = "POST";
 service.contentType = "multipart/form-data; boundary=—————————" + boundary;

 var content:String = "—————————" + boundary + "nr";
 content += 'Content-Disposition: form-data; name="uploadfile"; filename="' + fileName + '";' + "nr";
 content += 'Content-Type: text/plain' + "nrnr";
 content += inputText + "nr";
 content += "—————————" + boundary + "nr";
 content += 'Content-Disposition: form-data; name="Submit"' + "nr" + "Submit" + "nr";
 content += "—————————–" + boundary + "–nr";

 service.request = content;
 service.resultFormat = HTTPService.RESULT_FORMAT_E4X;

 if(faultHander != null){
 service.addEventListener(FaultEvent.FAULT, faultHander);
 }

 if(resultHandler != null){
 service.addEventListener(ResultEvent.RESULT,
 function httpResult(event:ResultEvent):void
 {
 var xml:XML = XML(event.result);
 trace("SERVER RESPONSE: " + xml);
 // Invoke your result handler here
 resultHandler(xml);
 }
 );
 }

 // Send Request
 service.send();
}


Leave a comment

5 Minutes on Java – A template implementation for configuration files

Loading properties or configurations for applications is a common task.  The process is generic and repeatable.  The following template implementation should provide an easy way to extend it based on application needs.

The design:

  • Template class: implements the algorithm and automates the process of initialising and loading/saving configuration files.
  • Implementation classes
  • A factory approach to consume all the implementations.

An Implementation

 public class Test{
 public static void main(String[] args) {
 PropertyFilesFactory.init();
 Properties properties = PropertyFilesFactory.getProperties("db");
 System.out.println("Testing: " + properties.getProperty("DB_MAX_CONNECTIONS"));
 }
 public class PropertyFilesFactory {

private static HashMap props = new HashMap();

public static void init(){

if(props.size() == 0){

// Create Configuration
 props.put("app", new AppPropertiesFileLoader());
 props.put("log", new LoggerPropertiesFileLoader());
 props.put("db" new IMDBPropertiesFileLoader());

// initialize configuration
 for(PropertiesFileTypes key : props.keySet()){
 props.get(key).init();

}

// post initialization
 for(PropertiesFileTypes key : props.keySet()){

props.get(key).postinit();

}

}

private static PropertiesFileLoader getConfig(String ct)

return props.get(ct);

}

public static Properties getProperties(String ct){

if(ct == null) return null;
 else return getConfig(ct).getProperties();

}

}

The Algorithm


package ez.cfg;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

import org.apache.log4j.Logger;

import ez.util.Constants;
import ez.util.Utility;

public abstract class PropertiesFileLoader {
 private static final Logger logger = Logger.getLogger(PropertiesFileLoader.class.getName());

 protected boolean justCreated = false;
 protected boolean initialized = false;
 protected Properties properties = new Properties();
 protected String fileName = "";

 public PropertiesFileLoader(String fileName){
 this.fileName = fileName;

 preinit();
 }

 // Mandatory: Client must override;
 abstract public void setup();

 // hook: client may not override unless needed
 public void postinit() {}

 public void preinit() {
 // Create Configdir
 File f = new File(Constants.CONFIG_DIR);
 if(f.exists() == false) {
 f.mkdir();
 }
 }

 // Can't override
 public final void init(){
 if(Utility.exists(fileName) == true){
 load();
 }
 else {
 justCreated = true;
 setup();

 save();

 load();
 }
 }
 synchronized final public void save(){
 File f = new File(fileName);
 FileOutputStream fos = null;

 try {
 fos = new FileOutputStream(f);
 if(properties.size() > 0){
 properties.store(fos, "");
 }
 else {
 logger.debug("Properites not setup, not writing to file!");
 }
 } catch (Exception e) {
 logger.error("Error while loading configuration: " + fileName);
 e.printStackTrace();
 } finally {
 try {
 if(fos != null) fos.close();

 if(justCreated == true){
 System.err.println("Config file " + fileName + " was just created, please fill it up before proceeding!");
 System.exit(1);
 }
 } catch (IOException e) {
 logger.error("Error while closing configuration: " + fileName);
 e.printStackTrace();
 }
 }
 }

 public final void load(){
 FileInputStream fis = null;

 try {
 File f = new File(fileName);
 fis = new FileInputStream(f);
 properties.load(fis);

 initialized = true;
 } catch (Exception e) {
 logger.error("Error while loading configuration: " + fileName);
 e.printStackTrace();
 } finally {
 try {
 if(fis != null) fis.close();
 } catch (IOException e) {
 logger.error("Error while closing configuration: " + fileName);
 e.printStackTrace();
 }
 }
 }

 public final Properties getProperties() {
 return properties;
 }

 public final boolean isInitialized(){
 return initialized;
 }

 public final boolean wasJustCreated() {
 return justCreated;
 }
}

Specialization for DataBase Configuration


package ez.cfg;

import java.io.File;

import ez.util.Constants;

public class IMDBPropertiesFileLoader extends PropertiesFileLoader {
 private static final String IMDB_CONFIG_FILE = Constants.CONFIG_DIR + File.separatorChar + "db.properties";

 public IMDBPropertiesFileLoader(){
 super(IMDB_CONFIG_FILE);
 }

 @Override
 public void setup(){
 properties.setProperty(Constants.DB_DRIVER_CLASS, "org.hsqldb.jdbcDriver");
 properties.setProperty(Constants.DB_URL, "jdbc:hsqldb:mem:feed_content_db");
 properties.setProperty(Constants.DB_USER, "sa");
 properties.setProperty(Constants.DB_PASSWORD, "");
 properties.setProperty(Constants.DB_MAX_CONNECTIONS, "2");
 }
}

Specialization for Logger Configuration


package ez.cfg;

import java.io.File;

import org.apache.log4j.PropertyConfigurator;

import ez.util.Constants;

public class LoggerPropertiesFileLoader extends PropertiesFileLoader {
 private static final String LOGGER_CONFIG_FILE = Constants.CONFIG_DIR + File.separatorChar + "logger-config.properties";

 public LoggerPropertiesFileLoader(){
 super(LOGGER_CONFIG_FILE);
 }

 @Override
 public void setup(){
 properties.setProperty("log4j.rootLogger", "debug, FILE");
 properties.setProperty("log4j.appender.FILE", "org.apache.log4j.FileAppender");
 properties.setProperty("log4j.appender.FILE.layout", "org.apache.log4j.PatternLayout");
 properties.setProperty("log4j.appender.FILE.File", "logs/diagnostic.log");
 properties.setProperty("log4j.appender.FILE.layout.ConversionPattern", "%d{ABSOLUTE} %5p %c{1}:%L - %m%n");
 }

 @Override
 public void postinit(){
 PropertyConfigurator.configure(properties);
 }
}

Constants used


package ez.util;

import java.io.File;

public interface Constants {
 public static final String CONFIG_DIR = "config";
 public static final String DATA_DIR = "data";
 
 public static final String HTTP_TIMEOUT = "HTTP_TIMEOUT";
 public static final String OUTPUT_FILE_STORE = "OutputFileStore";
 

 public static final String DB_DRIVER_CLASS = "JDBC.DRIVER";
 public static final String DB_USER = "USER";
 public static final String DB_PASSWORD = "PASSWORD";
 public static final String DB_MAX_CONNECTIONS = "CONNECTIONS";
 public static final String DB_URL = "JDBC.URL";
}