Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Dynamic Proxies - Short Tutorial

JavaFAQ Home » Story by Dr. Kabutz Go to all tips in Story by Dr. Kabutz


Bookmark and Share The Java Specialists' Newsletter [Issue 005] - Dynamic Proxies - Short Tutorial
Author: Dr. Christoph G. Jung

You can subscribe from our home page: http://www.javaspecialists.co.za (which also hosts all previous issues, available free of charge Smile


This free advanced Java newsletter is wholly funded by Maximum Solutions, your partner in Object Orientation and Java. How can we help you in your project? Heinz


Welcome to our fifth "The Java(tm) Specialists' Newsletter", published by Maximum Solutions, the company who may not be good at Java(tm), but Java is all we do, so we call ourselves "Java Specialists". Thank you for not unsubscribing in hordes (hmmm, I have not told you HOW to unsubscribe, so maybe that's why Wink

Isn't it funny how employment agencies ask you ALL the things you know, like "which word processor have you used?" and "what version of Turbo Pascal do you know?" What relevance is that to today's newsletter? None.

Anyway, we've had an interesting week sorting out small Java problems and fixing bugs in my software. Many thanks to Dr. Christoph for writing this week's newsletter, which I really enjoyed reading. For this I owe you an Esplendido! Christoph started writing Java code at the end of 1999 for a very innovative ERP company in Germany called infor Business Solutions AG, and has quickly become a real fundi at writing application server code. Prior to that, he did a doctorate in Computer Science with emphasis on Robotics and Artificial Intelligence. I don't know where Java comes in, but a PhD is general education that is useful for many spheres of life, and it does not really matter what your topic was. Believe me, my PhD topic was even less useful Wink

Anyway, enough from me, here is a "Short Tutorial to the Java2 platform Dynamic Proxy Facilities" ....... I wish we had known about this before we started pasting access control onto our 570'000 line application ......

Short Tutorial to the Java2(TM) platform Dynamic Proxy Facilities

C.G.Jung (schorsch@javaspecialists.co.za)

A Bad Example

One the most useful design patterns when it comes to building extensible frameworks turns out to be the PROXY pattern. For example, imagine your notoriously paniqued project manager insisting on your introducing new security features into your companies existing business model:

/**
 * A Class representing a single salary
 */
class Salary {
  Employee employee;
  long amount;

  public long getAmount() {
    return amount;
  }
}

Your straightforward approach to shield the objects from exporting sensible information, such as exorbitant management salaries, to ordinary users, such as you humble worm, would be to introduce a dedicated SecurityChecker (this is not a java.lang.Security tutorial, so please excuse the following very naive code):

/**
 * Realises The Systems Security Policies
 */
class SecurityChecker {
  java.security.Permission manyBucksPermission;

  long check(long amount) throws SecurityException {
    if(amount>1000000)
      SecurityManager.checkPermission(manyBucksPermission);
    return amount;
  }
}
/**
 * A Modified Salary that is "Too-Much-Bucks"-Aware
 */

class Salary {
  Employee employee;
  long amount;
  // ugly reference
  static SecurityChecker sc;

  public long getAmount() {
    // isnt this the wrong place for doing that?
    return sc.check(amount);
  }
}

Now your project manager is happy because of being able to ask for his next salary increase. But, you (and your colleague that is the application but not the framework specialist) will quite likely curse him three times when he returns with next terms project plan that includes

  1. heavily extending the business logic (amount will no more be stored immediately, but computed by a very complex, profile-oriented function, an additional int getAmount() is needed in Salary, an Order should be implemented, etc.)
  2. expanding the successfully introduced security policies (maybe a check(Customer customer) should be added that restricts access to data associated with particular "high-sensitive" customers).

The reason for your deadly wishes is of course that in the above solution, we have heavily mixed up application data and methods (such as amount and long getAmount() ) with generic access control (such as check(long amount)) Extending and updating the 200 classes with 1000 methods of application logic involves understanding of when and how to correctly apply the available security checks. Because only you as the framework pro are able to do that, you will end up with a quite suboptimal division of responsibility and code.

The Proxy Solution

In order to free your colleague from the heavy burden of the security framework and enable him to concentrate on his business, the better choice is hence to leave his Salary class alone, but rather provide him with an inherited PROXY class that intercepts any getAmount() calls to interface the security framework:

/**
 * proxy that behaves as a salary
 * and that performs a security check
 * before delegation
 */

class SalarySecurityProxy extends Salary {
  // this is not application, hence the reference is ok
  static SecurityChecker sc;
  // the object to which we delegate the calls to
  Salary realObject;

  public long getAmount() {
    // framework call after delegation
    return sc.check(realObject.getAmount());
  }
}

Now, your collegue is free to change and extend the application logic to realise project goal a (e.g., manipulating amount and getAmount()), while you can add additional independently further proxies and intercepting/ delegation calls to pursue project goal b. Strike.

If your initial application design has been smart by using mucho, mucho interfaces (you know that you should do that anyway, don?t you?), PROXY can be even made compatible with complex inheritances:

/** use interfaces everywhere in your app-logic */
interface Salary {
...
}
/** and provide proper implementations */
class SalaryImpl implements Salary{
...
}
/** as well as framework proxies */
class SalarySecurityProxy implements Salary{
...
}
/** when you extend your model ... */
interface ManagementSalary extends Salary {
...
}
/** ... afterwards ... */
class ManagementSalaryImpl extends SalaryImpl {
...
}
/** ... it's very easy */
class ManagementSalarySecurityProxy extends SalarySecurityProxy {
...
}

Double Strike.

The possibilities of the proxy are nearly endless and range from transparent SECURITY over LAZY RETRIEVAL, POOLING, CACHING, and TRANSACTIONAL MARKUP up to DISTRIBUTION (remember RMI stubs?). It is highly useful to combine such differently focused proxies in a CHAIN OF RESPONSIBILITY to a complex, at the same time extensible framework, e.g., SalarySecurityProxy (performs security checks) --> SalaryPersistenceProxy (retrieves the "real" salary from a database) --> Salary

Often, PROXY is used in combination with the FACTORY pattern in order to allow the transparent insertion of proxies and chains into the application logic (your colleague would?nt be bothered by their construction at all ... no more endless discussions ... no more fruitless explanations ... must be like heaven).

Why Dynamic Proxies are needed

However, the main drawback of PROXY is that for each application class, each application method, and each additional framework functionality, you have to implement and maintain (sic!) a dedicated interceptor class/method. Depending on the output of your colleague, this can be quite a pain in the ass ... (BTW: I?m sure that some of you already collided with the winding RMIC procedure which actually is an automated proxy-generator and -compiler not to speak of its ubiquitious stub-deployment problem)

If reminding the mostly general nature of framework code, you ask yourself whether there is not a better solution to this issue. Actually, there is. It is called DYNAMIC PROXIES and one of the wonderful invents that came to your harddisk with your JRE/JDK1.3 installation.

DYNAMIC PROXIES heavily rely on the already matured reflection capabilities of the Java2 platform. They separate the "interception logic", that is the part of simulating an arbitrary interface, from the "invocation logic", that is the part of calling the framework before or after delegating any method call to the proper application target.

The "invocation logic", such as to connect to a method-based security checker, is realised on purpose by implementing the freshly introduced java.lang.reflect.InvocationHandler interface (more specifically, its reflection-based invoke-Method):

/**
 * a generic, method-based security handler
 * that is not only useful for Salaries
 */

class SecurityHandler extends InvocationHandler {
  static SecurityChecker sc;
  final Object realObject;

  /** contructor accepts the real subject */
  public SecurityHandler(Object real) {
    realObject=real;
  }

  /** a generic, reflection-based secure invocation */
  public Object invoke(Object target,
      java.lang.reflect.Method method, Object[] arguments)
      throws Throwable {
    try{
      // call framework and then reflect the app-logic
      return sc.check(method).invoke(realObject,arguments);
    } catch(java.lang.reflect.InvocationTargetException e) {
      // reconvert nested application exceptions
      throw e.getTargetException();
    }
  }
}

The "interception logic" is already hardwired into the 1.3 vm and the new java.lang.reflect.Proxy class. All it requires to combine it with the above SecurityHandler code is to call the static:

ManagementSalary salary;

ManagementSalary smellsLikeSalary=(ManagementSalary)
  java.lang.reflect.Proxy.newProxyInstance(
    Salary.class.getClassLoader(),
    new Class[] {ManagementSalary.class},
    new SecurityHandler(salary));

The thus constructed smellsLikeSalary object now behaves like an implementation of ManagementSalary. In fact, it *IS* an implementation of ManagementSalary whose class has been dynamically constructed at runtime, hence dynamically. You can inspect it (smellsLikeSalary instanceof ManagementSalary), cast it ((Salary) smellsLikeSalary) and call methods on it (smellsLikeSalary.getAmount()). Method calls will in turn be dispatched to the invoke method of the given invocation handler (where in our example, target points to smellsLikeSalary, method points to the internal Salary.getAmount() representation, and the arguments array is empty). Return values and exceptions will be automatically converted/casted into the compatible types as given in the interface signature. That?s it.

(No, actually that?s not: java.lang.reflect.Proxy has a lot more advanced features and there are some tricky considerations when building proxies for multiple/conflicting interfaces - but that?s too much for now, please refer to the API documentation for these issues.)

If PROXY has broad applicability, this holds for DYNAMIC PROXIES even more. For example, you could imagine a PersistenceHandler that hides JDBC-access to a row in a relational database table without requiring any additional object instances. For example, you could think of a JRMPRemoteHandler that implements stub-less (HHHOOOORRRAAAYYYY ... no more RMIC) RMI-access to a remote object via the TCP/IP-based Java Remote Method Protocol.

The latter usage is especially supported by DYNAMIC PROXIES, such as smellsLikeSalary actually being serializable, if the tied handler classes are. Under http://www.dreambean.com/download/rickard/SmartWorld-1.2.zip you will find executable code and documentation that extends SUN-JRMP1.2 with suitable handlers that can be distributed through naming services, files, etc. and that can be straightforwardly enriched by load-balancing, failover, clustering, and connection-pooling features.

The first (Open Source!) EJB product that uses these handlers instead of remote stubs is jBoss whose complementary server container design is indeed realised as flexible CHAIN OF RESPONSIBILITY ... Long live the (DYNAMIC) PROXIES!


Thanks for that, Christoph...

Next week will be a bit shorter and I will show you how to put method bodies in Java interfaces, which you should never need to do, IF the framework you are working within is perfect. In a less-than-perfect world such a technique can be useful, as fellow fish-chaser Niko Brummer told me. So, hold your breath until next week.

Regards

Heinz and Christoph


Copyright 2000-2003 Maximum Solutions, South Africa

Reprint Rights. Copyright subsists in all the material included in this email, but you may freely share the entire email with anyone you feel may be interested, and you may reprint excerpts both online and offline provided that you acknowledge the source as follows: This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

Java and Sun are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Maximum Solutions is independent of Sun Microsystems, Inc.


 Printer Friendly Page  Printer Friendly Page
 Send to a Friend  Send to a Friend

.. Bookmark and Share

Search here again if you need more info!
Custom Search



Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy