MrUll's

Juli 28, 2004

a basic OO concept

i read a basic statement about OO which is worth to be memorized. often i heard the phase to delegate sth to another class. a vague understanding states that this is to be accomplished using a method call on another object. having separation of varying concerns in mind, a delegation of functionality means a method call on another object, passing an objects self-reference (this).

e.g. in a first step this allows the separation of data and functionality from a class, a second step could impose another functionality. this is not far away from being called strategy pattern.

c-style; doing and data in same Object:

public void solveProblem( int how ) {
 switch (how) {
   case QUICKANDDIRTY: doItQuickAndDirty(); break;
   case SECURED: doTransactionalProcessed(); break;
}
}

OO approach using delegation (strategy):

public void solveProblem( iHowToBeProcessed processor ) {
 processor.doItYourWay( this );


iHowToBeProcessed is an Interface; implementations are realizing e.g. quick-and-dirty or secured processings. This allows to introduce additional processings without affecting the
class to be modified on which processing has to be done.

Juli 26, 2004

using "double dispatch" technique to implement a visitor pattern

visitor gof pattern is easy to unterstand when you know how "double dispatch" works. To refresh your mind, use it when you have to implement some operations on the elements of a object structure. an example is to generate a special XML representation, maybe representing a personalized view. the elements of the structure rarely change but its to be expected that some new operations are to be coded sooner or later. you like to keep the objectstructure separated from code to do a desired operation, means you dont want to implement operation-specific methods in your objectstructure classes. with this an an objectstructure which will rarely change things go like this:
for each desired operation a "visitor" has to be implemented, e.g. three operations over a structure of objects means that there a three implementations of the visitor interface. for each element in the structure a visitor implements a callback method. all elements offer an entrypoint for a visitor. with this, a client instantiates a visitor, iterates over the elements, and passes the visitor to the element. The element then calls his callback method on the passed visitor. this means the element passes himself as actual parameter. look at the following example. (structure contains only two elements)

public interface Visitor {
public void visitConcreteElement(Element1 element1);
public void visitConcreteElement(Element2 element2);
}

public class ConcreteVisitor implements Visitor {
public void visitConcreteElement(Element1 elem) {
elem.operationA();
}
public void visitConcreteElement(Element2 elem) {
elem.operationB();
}
}

public interface Element {
public void accept(Visitor v);
}

// Element2 similar
public class Element1 implements Element {
public void accept(Visitor v) {
v.visitConcreteElement(this);
}
public void operationA() {
System.out.println("Element1 :: Element1.operationA() executing");
}


processing over structure then goes like this:

visitor = new ConcreteVisitor();
for (Iterator iter = objectStruct.iterator(); iter.hasNext();) {
((Element) iter.next()).accept(visitor);
}

Note that this separates processing from the data structures. As processing comes from outside (the visitor), the elements have to publish some additional methods, but operation-scoped methods are drawn to the visitor.

Juli 22, 2004

Basic double dispatching OO pattern

At the moment, i'm reading "J2EE Design and Development, Wrox Press"; herein the author promotes four approaches to generating XML from a set of Java Objects. (annot. backwards jakarta commons "digester" is perhaps suitable). One strategy is using the visitor pattern. i refreshed my mind on this and noticed a concept called "double dispatching" i never heared before. so i made up my mind about this. there are some statements about it and its worth to note that the Visiter is a specific double-dispatch technique.
 
ootips.org stated:
dual or double dispatch means a function call that depends on two of its arguments. OO usually supports single dispatch - the call is dynamically dispatched based on the object's type, but not on the type of any of the arguments.
 
vince huston on his site:
OO messages routinely manifest "single dispatch" - the operation that is executed depends on: the name of the request, and the type of the receiver. In "double dispatch", the operation executed depends on: the name of the request, and the type of TWO receivers (the type of the Visitor and the type of the element it visits).

With this things are getting clearer: two receivers (of a call) means that there has to be a second call. Maybe a recall to the call-generating object (initiator) or a call to an object passed as actual parameter (... a command object).  this technique allows e.g. to prevent instanceof decisions and/or downcasts  (to dispatch work based on the type). Actual parameter for the second call is often the instance of the actual object whos method is called - this.

use double dispatch for a highlevel separation of concerns (or to obfuscate code ...). 
If code like this is present:

public class DocWorkflow implements iDocWorkflow {
...
public void shiftToNextView( businessDocument doc) {

  if(doc instanceof businessTextDoc) { 
       this.shiftToCatalogueDept((businessTextDoc) doc);
       ...
  }
if(doc instanceof businessPricingDoc) ....
}
...
private void shiftToCatalogueDept( businessTextDoc x) { ... }

private void shiftToPurchasingDept( businessPricingDoc x) { ... }
... 

to introduce double dispatch: why not let the specific document type itself decide which concrete step is next ? (imagine 45 doc types and some additional special code, maybe a doc split or hiding some data ...). This would result in a large spaghetticode. first is to change private shift methods to protected to allow access. then, introduce a backward call:

public shiftToNextView( businessDocument doc) {
  ...
  doc.shiftToNextView(this);
  ...
}

in e.g. class businessTextDoc (subclass of businessDocument):

protected shiftToNextView( iDocWorkflow iwf ) {

iwf.shiftToCatalogueDept(this);

}

With this, no downcasting is required any more (potential risks at runtime)

 















Juli 09, 2004

decoding strings containing html entities (clientside,javascript)

sometimes it makes sense doing some clientside string processing in a javascript environment. maybe some business logic has to be implemented. for example a check wether an modified string (user provided or internal-generic generated) does not exceed a specific length. imagine a db field has a type of VARCHAR2(13) (oracle). there is an upper limit of ten chars (encoding of stored chars is oracle db character set chosen on installtime, e.g. WE8ISO8859P15 wich is ISO Latin9). JDBC Thin Layer or Oracle Net perform a transparent char conversion. Code of the euro currency sign on Window clients (codepage 1252) is 0x80, but a oracle db running a ISO Latin9 db charset has to store 0xA4 because in ISO Latin 9 euro occupies this code position. (note that position 0x80 is not defined for ISO Latin, so problems are to be expected when doing oracle exp/imp if euros are stored there). maybe some people think that decoding html entities is better bound to the business layer as there is a specific platform present. With an varchar2(13) storage a submission of a string value "price is 10 €" is ok. But what if input is "price is 10 €". to prevent submission and network roundtrips, a js-maxlength check makes sense or to go a step further, a decoding would be nice, so that users doesnt have to worry. thanks to andy oakley, the following javascript function is appropiate. note that for % - escaped strings, you can use excape() and unexcape() as javascript buildins. htmlDecode takes an entity encoded string and returns a decoded representation. See code:


function htmlDecode(s)
{
      var out = "";
      if (s==null) return;
      var l = s.length;
      for (var i=0; i      {
            var ch = s.charAt(i);
            if (ch == '&')
            {
            var semicolonIndex = s.indexOf(';', i+1);
            if (semicolonIndex > 0)
            {
         var entity = s.substring(i + 1, semicolonIndex);
         if (entity.length > 1 && entity.charAt(0) == '#')
         {
               if (entity.charAt(1) == 'x' || entity.charAt(1) == 'X')
                     ch = String.fromCharCode(eval('0'+entity.substring(1)));
               else
                     ch = String.fromCharCode(eval(entity.substring(1)));
         }
     else
       {
               switch (entity)
                              {
      case 'amp': ch = String.fromCharCode(0x0026); break;
      case 'lt': ch = String.fromCharCode(0x003c); break;
      case 'gt': ch = String.fromCharCode(0x003e); break;
      case 'nbsp': ch = String.fromCharCode(0x00a0); break;
      case 'iexcl': ch = String.fromCharCode(0x00a1); break;
      case 'cent': ch = String.fromCharCode(0x00a2); break;
      case 'pound': ch = String.fromCharCode(0x00a3); break;
      case 'curren': ch = String.fromCharCode(0x00a4); break;
      case 'yen': ch = String.fromCharCode(0x00a5); break;
      case 'brvbar': ch = String.fromCharCode(0x00a6); break;
      case 'sect': ch = String.fromCharCode(0x00a7); break;
      case 'uml': ch = String.fromCharCode(0x00a8); break;
      case 'copy': ch = String.fromCharCode(0x00a9); break;
      case 'ordf': ch = String.fromCharCode(0x00aa); break;
      case 'laquo': ch = String.fromCharCode(0x00ab); break;
      case 'not': ch = String.fromCharCode(0x00ac); break;
      case 'shy': ch = String.fromCharCode(0x00ad); break;
      case 'reg': ch = String.fromCharCode(0x00ae); break;
      case 'macr': ch = String.fromCharCode(0x00af); break;
      case 'deg': ch = String.fromCharCode(0x00b0); break;
      case 'plusmn': ch = String.fromCharCode(0x00b1); break;
      case 'sup2': ch = String.fromCharCode(0x00b2); break;
      case 'sup3': ch = String.fromCharCode(0x00b3); break;
      case 'acute': ch = String.fromCharCode(0x00b4); break;
      case 'micro': ch = String.fromCharCode(0x00b5); break;
      case 'para': ch = String.fromCharCode(0x00b6); break;
      case 'middot': ch = String.fromCharCode(0x00b7); break;
      case 'cedil': ch = String.fromCharCode(0x00b8); break;
      case 'sup1': ch = String.fromCharCode(0x00b9); break;
      case 'ordm': ch = String.fromCharCode(0x00ba); break;
      case 'raquo': ch = String.fromCharCode(0x00bb); break;
      case 'frac14': ch = String.fromCharCode(0x00bc); break;
      case 'frac12': ch = String.fromCharCode(0x00bd); break;
      case 'frac34': ch = String.fromCharCode(0x00be); break;
      case 'iquest': ch = String.fromCharCode(0x00bf); break;
      case 'Agrave': ch = String.fromCharCode(0x00c0); break;
      case 'Aacute': ch = String.fromCharCode(0x00c1); break;
      case 'Acirc': ch = String.fromCharCode(0x00c2); break;
      case 'Atilde': ch = String.fromCharCode(0x00c3); break;
      case 'Auml': ch = String.fromCharCode(0x00c4); break;
      case 'Aring': ch = String.fromCharCode(0x00c5); break;
      case 'AElig': ch = String.fromCharCode(0x00c6); break;
      case 'Ccedil': ch = String.fromCharCode(0x00c7); break;
      case 'Egrave': ch = String.fromCharCode(0x00c8); break;
      case 'Eacute': ch = String.fromCharCode(0x00c9); break;
      case 'Ecirc': ch = String.fromCharCode(0x00ca); break;
      case 'Euml': ch = String.fromCharCode(0x00cb); break;
      case 'Igrave': ch = String.fromCharCode(0x00cc); break;
      case 'Iacute': ch = String.fromCharCode(0x00cd); break;
      case 'Icirc': ch = String.fromCharCode(0x00ce ); break;
      case 'Iuml': ch = String.fromCharCode(0x00cf); break;
      case 'ETH': ch = String.fromCharCode(0x00d0); break;
      case 'Ntilde': ch = String.fromCharCode(0x00d1); break;
      case 'Ograve': ch = String.fromCharCode(0x00d2); break;
      case 'Oacute': ch = String.fromCharCode(0x00d3); break;
      case 'Ocirc': ch = String.fromCharCode(0x00d4); break;
      case 'Otilde': ch = String.fromCharCode(0x00d5); break;
      case 'Ouml': ch = String.fromCharCode(0x00d6); break;
      case 'times': ch = String.fromCharCode(0x00d7); break;
      case 'Oslash': ch = String.fromCharCode(0x00d8); break;
      case 'Ugrave': ch = String.fromCharCode(0x00d9); break;
      case 'Uacute': ch = String.fromCharCode(0x00da); break;
      case 'Ucirc': ch = String.fromCharCode(0x00db); break;
      case 'Uuml': ch = String.fromCharCode(0x00dc); break;
      case 'Yacute': ch = String.fromCharCode(0x00dd); break;
      case 'THORN': ch = String.fromCharCode(0x00de); break;
      case 'szlig': ch = String.fromCharCode(0x00df); break;
      case 'agrave': ch = String.fromCharCode(0x00e0); break;
      case 'aacute': ch = String.fromCharCode(0x00e1); break;
      case 'acirc': ch = String.fromCharCode(0x00e2); break;
      case 'atilde': ch = String.fromCharCode(0x00e3); break;
      case 'auml': ch = String.fromCharCode(0x00e4); break;
      case 'aring': ch = String.fromCharCode(0x00e5); break;
      case 'aelig': ch = String.fromCharCode(0x00e6); break;
      case 'ccedil': ch = String.fromCharCode(0x00e7); break;
      case 'egrave': ch = String.fromCharCode(0x00e8); break;
      case 'eacute': ch = String.fromCharCode(0x00e9); break;
      case 'ecirc': ch = String.fromCharCode(0x00ea); break;
      case 'euml': ch = String.fromCharCode(0x00eb); break;
      case 'igrave': ch = String.fromCharCode(0x00ec); break;
      case 'iacute': ch = String.fromCharCode(0x00ed); break;
      case 'icirc': ch = String.fromCharCode(0x00ee); break;
      case 'iuml': ch = String.fromCharCode(0x00ef); break;
      case 'eth': ch = String.fromCharCode(0x00f0); break;
      case 'ntilde': ch = String.fromCharCode(0x00f1); break;
      case 'ograve': ch = String.fromCharCode(0x00f2); break;
      case 'oacute': ch = String.fromCharCode(0x00f3); break;
      case 'ocirc': ch = String.fromCharCode(0x00f4); break;
      case 'otilde': ch = String.fromCharCode(0x00f5); break;
      case 'ouml': ch = String.fromCharCode(0x00f6); break;
      case 'divide': ch = String.fromCharCode(0x00f7); break;
      case 'oslash': ch = String.fromCharCode(0x00f8); break;
      case 'ugrave': ch = String.fromCharCode(0x00f9); break;
      case 'uacute': ch = String.fromCharCode(0x00fa); break;
      case 'ucirc': ch = String.fromCharCode(0x00fb); break;
      case 'uuml': ch = String.fromCharCode(0x00fc); break;
      case 'yacute': ch = String.fromCharCode(0x00fd); break;
      case 'thorn': ch = String.fromCharCode(0x00fe); break;
      case 'yuml': ch = String.fromCharCode(0x00ff); break;
      case 'OElig': ch = String.fromCharCode(0x0152); break;
      case 'oelig': ch = String.fromCharCode(0x0153); break;
      case 'Scaron': ch = String.fromCharCode(0x0160); break;
      case 'scaron': ch = String.fromCharCode(0x0161); break;
      case 'Yuml': ch = String.fromCharCode(0x0178); break;
      case 'fnof': ch = String.fromCharCode(0x0192); break;
      case 'circ': ch = String.fromCharCode(0x02c6); break;
      case 'tilde': ch = String.fromCharCode(0x02dc); break;
      case 'Alpha': ch = String.fromCharCode(0x0391); break;
      case 'Beta': ch = String.fromCharCode(0x0392); break;
      case 'Gamma': ch = String.fromCharCode(0x0393); break;
      case 'Delta': ch = String.fromCharCode(0x0394); break;
      case 'Epsilon': ch = String.fromCharCode(0x0395); break;
      case 'Zeta': ch = String.fromCharCode(0x0396); break;
      case 'Eta': ch = String.fromCharCode(0x0397); break;
      case 'Theta': ch = String.fromCharCode(0x0398); break;
      case 'Iota': ch = String.fromCharCode(0x0399); break;
      case 'Kappa': ch = String.fromCharCode(0x039a); break;
      case 'Lambda': ch = String.fromCharCode(0x039b); break;
      case 'Mu': ch = String.fromCharCode(0x039c); break;
      case 'Nu': ch = String.fromCharCode(0x039d); break;
      case 'Xi': ch = String.fromCharCode(0x039e); break;
      case 'Omicron': ch = String.fromCharCode(0x039f); break;
      case 'Pi': ch = String.fromCharCode(0x03a0); break;
      case ' Rho ': ch = String.fromCharCode(0x03a1); break;
      case 'Sigma': ch = String.fromCharCode(0x03a3); break;
      case 'Tau': ch = String.fromCharCode(0x03a4); break;
      case 'Upsilon': ch = String.fromCharCode(0x03a5); break;
      case 'Phi': ch = String.fromCharCode(0x03a6); break;
      case 'Chi': ch = String.fromCharCode(0x03a7); break;
      case 'Psi': ch = String.fromCharCode(0x03a8); break;
      case 'Omega': ch = String.fromCharCode(0x03a9); break;
      case 'alpha': ch = String.fromCharCode(0x03b1); break;
      case 'beta': ch = String.fromCharCode(0x03b2); break;
      case 'gamma': ch = String.fromCharCode(0x03b3); break;
      case 'delta': ch = String.fromCharCode(0x03b4); break;
      case 'epsilon': ch = String.fromCharCode(0x03b5); break;
      case 'zeta': ch = String.fromCharCode(0x03b6); break;
      case 'eta': ch = String.fromCharCode(0x03b7); break;
      case 'theta': ch = String.fromCharCode(0x03b8); break;
      case 'iota': ch = String.fromCharCode(0x03b9); break;
      case 'kappa': ch = String.fromCharCode(0x03ba); break;
      case 'lambda': ch = String.fromCharCode(0x03bb); break;
      case 'mu': ch = String.fromCharCode(0x03bc); break;
      case 'nu': ch = String.fromCharCode(0x03bd); break;
      case 'xi': ch = String.fromCharCode(0x03be); break;
      case 'omicron': ch = String.fromCharCode(0x03bf); break;
      case 'pi': ch = String.fromCharCode(0x03c0); break;
      case 'rho': ch = String.fromCharCode(0x03c1); break;
      case 'sigmaf': ch = String.fromCharCode(0x03c2); break;
      case 'sigma': ch = String.fromCharCode(0x03c3); break;
      case 'tau': ch = String.fromCharCode(0x03c4); break;
      case 'upsilon': ch = String.fromCharCode(0x03c5); break;
      case 'phi': ch = String.fromCharCode(0x03c6); break;
      case 'chi': ch = String.fromCharCode(0x03c7); break;
      case 'psi': ch = String.fromCharCode(0x03c8); break;
      case 'omega': ch = String.fromCharCode(0x03c9); break;
      case 'thetasym': ch = String.fromCharCode(0x03d1); break;
      case 'upsih': ch = String.fromCharCode(0x03d2); break;
      case 'piv': ch = String.fromCharCode(0x03d6); break;
      case 'ensp': ch = String.fromCharCode(0x2002); break;
      case 'emsp': ch = String.fromCharCode(0x2003); break;
      case 'thinsp': ch = String.fromCharCode(0x2009); break;
      case 'zwnj': ch = String.fromCharCode(0x200c); break;
      case 'zwj': ch = String.fromCharCode(0x200d); break;
      case 'lrm': ch = String.fromCharCode(0x200e); break;
      case 'rlm': ch = String.fromCharCode(0x200f); break;
      case 'ndash': ch = String.fromCharCode(0x2013); break;
      case 'mdash': ch = String.fromCharCode(0x2014); break;
      case 'lsquo': ch = String.fromCharCode(0x2018); break;
      case 'rsquo': ch = String.fromCharCode(0x2019); break;
      case 'sbquo': ch = String.fromCharCode(0x201a); break;
      case 'ldquo': ch = String.fromCharCode(0x201c); break;
      case 'rdquo': ch = String.fromCharCode(0x201d); break;
      case 'bdquo': ch = String.fromCharCode(0x201e); break;
      case 'dagger': ch = String.fromCharCode(0x2020); break;
      case 'Dagger': ch = String.fromCharCode(0x2021); break;
      case 'bull': ch = String.fromCharCode(0x2022); break;
      case 'hellip': ch = String.fromCharCode(0x2026); break;
      case 'permil': ch = String.fromCharCode(0x2030); break;
      case 'prime': ch = String.fromCharCode(0x2032); break;
      case 'Prime': ch = String.fromCharCode(0x2033); break;
      case 'lsaquo': ch = String.fromCharCode(0x2039); break;
      case 'rsaquo': ch = String.fromCharCode(0x203a); break;
      case 'oline': ch = String.fromCharCode(0x203e); break;
      case 'frasl': ch = String.fromCharCode(0x2044); break;
      case 'euro': ch = String.fromCharCode(0x20ac); break;
      case 'image': ch = String.fromCharCode(0x2111); break;
      case 'weierp': ch = String.fromCharCode(0x2118); break;
      case 'real': ch = String.fromCharCode(0x211c); break;
      case 'trade': ch = String.fromCharCode(0x2122); break;
      case 'alefsym': ch = String.fromCharCode(0x2135); break;
      case 'larr': ch = String.fromCharCode(0x2190); break;
      case 'uarr': ch = String.fromCharCode(0x2191); break;
      case 'rarr': ch = String.fromCharCode(0x2192); break;
      case 'darr': ch = String.fromCharCode(0x2193); break;
      case 'harr': ch = String.fromCharCode(0x2194); break;
      case 'crarr': ch = String.fromCharCode(0x21b5); break;
      case 'lArr': ch = String.fromCharCode(0x21d0); break;
      case 'uArr': ch = String.fromCharCode(0x21d1); break;
      case 'rArr': ch = String.fromCharCode(0x21d2); break;
      case 'dArr': ch = String.fromCharCode(0x21d3); break;
      case 'hArr': ch = String.fromCharCode(0x21d4); break;
      case 'forall': ch = String.fromCharCode(0x2200); break;
      case 'part': ch = String.fromCharCode(0x2202); break;
      case 'exist': ch = String.fromCharCode(0x2203); break;
      case 'empty': ch = String.fromCharCode(0x2205); break;
      case 'nabla': ch = String.fromCharCode(0x2207); break;
      case 'isin': ch = String.fromCharCode(0x2208); break;
      case 'notin': ch = String.fromCharCode(0x2209); break;
      case 'ni': ch = String.fromCharCode(0x220b); break;
      case 'prod': ch = String.fromCharCode(0x220f); break;
      case 'sum': ch = String.fromCharCode(0x2211); break;
      case 'minus': ch = String.fromCharCode(0x2212); break;
      case 'lowast': ch = String.fromCharCode(0x2217); break;
      case 'radic': ch = String.fromCharCode(0x221a); break;
      case 'prop': ch = String.fromCharCode(0x221d); break;
      case 'infin': ch = String.fromCharCode(0x221e); break;
      case 'ang': ch = String.fromCharCode(0x2220); break;
      case 'and': ch = String.fromCharCode(0x2227); break;
      case 'or': ch = String.fromCharCode(0x2228); break;
      case 'cap': ch = String.fromCharCode(0x2229); break;
      case 'cup': ch = String.fromCharCode(0x222a); break;
      case 'int': ch = String.fromCharCode(0x222b); break;
      case 'there4': ch = String.fromCharCode(0x2234); break;
      case 'sim': ch = String.fromCharCode(0x223c); break;
      case 'cong': ch = String.fromCharCode(0x2245); break;
      case 'asymp': ch = String.fromCharCode(0x2248); break;
      case 'ne': ch = String.fromCharCode(0x2260); break;
      case 'equiv': ch = String.fromCharCode(0x2261); break;
      case 'le': ch = String.fromCharCode(0x2264); break;
      case 'ge': ch = String.fromCharCode(0x2265); break;
      case 'sub': ch = String.fromCharCode(0x2282); break;
      case 'sup': ch = String.fromCharCode(0x2283); break;
      case 'nsub': ch = String.fromCharCode(0x2284); break;
      case 'sube': ch = String.fromCharCode(0x2286); break;
      case 'supe': ch = String.fromCharCode(0x2287); break;
      case 'oplus': ch = String.fromCharCode(0x2295); break;
      case 'otimes': ch = String.fromCharCode(0x2297); break;
      case 'perp': ch = String.fromCharCode(0x22a5); break;
      case 'sdot': ch = String.fromCharCode(0x22c5); break;
      case 'lceil': ch = String.fromCharCode(0x2308); break;
      case 'rceil': ch = String.fromCharCode(0x2309); break;
      case 'lfloor': ch = String.fromCharCode(0x230a); break;
      case 'rfloor': ch = String.fromCharCode(0x230b); break;
      case 'lang': ch = String.fromCharCode(0x2329); break;
      case 'rang': ch = String.fromCharCode(0x232a); break;
      case 'loz': ch = String.fromCharCode(0x25ca); break;
      case 'spades': ch = String.fromCharCode(0x2660); break;
      case 'clubs': ch = String.fromCharCode(0x2663); break;
      case 'hearts': ch = String.fromCharCode(0x2665); break;
      case 'diams': ch = String.fromCharCode(0x2666); break;
      default: ch = '?'; break;
                              }
                        }
                        i = semicolonIndex;
                  }
            }
            out += ch;
      }
      return out;
}

Juli 08, 2004

a simple way for inspecting TCP traffic (HTTP, SOAP, XMLRPC)

Apaches Java SOAP implementation library contains some valueable utilities. in particular, two TCP tunneling tools are quite useful, even for general purposes. they are implemented in java, so a java runtime installation is enaugh for testing. the first runs without a GUI and simply tunnels TCP Traffic. As parameters you have to specify listening port, serverhostname and port. e.g. with 8889 wsrv 8080 as actual parameters the tunneling tool listens on port 8889 to redirect traffic to and from server "wsrv" on port 8080. the second version of the tool has offers request and response content via a simple gui in separated windows. this sniffer allows to have a look on soap or html request-response content.

to install, download the latest edition of the apache soap implementation. (for doing soap, apache axis is a followup framework). latest version of soap.jar is 2.3.1.

Download from http://ws.apache.org/soap/ , then unzip and have a look into directory lib. only jar file in there is soap.jar. within you can use org.apache.soap.util.net.TcpTunnelGui and org.apache.soap.util.net.TcpTunnel as a standalone java app from the commandline.
to invoke use:

java -cp ./soap.jar org.apache.soap.util.net.TcpTunnelGui 8099 localhost 8080

if your webserver or servlet container listens on port 8080, a request to localhost:8099 is done via this java app. request and response contents are logged in separate windows.

Juli 06, 2004

Eclipse 3, deleting & undeleting files ...

i deleted a sourcefile by mistake using the navigtor within Eclipse3. its worth to be mentioned that files get really deleted with this. no chance to undo like having deleted files via M$ Explorer. But as being a really platform/OS independent (java) tool, Eclipse offers a buildin feature for restoring files. Access is done via "Restory from local History ..." via Navigator.