Abstract This document presents the concepts of frameworks and proxies and the work done during the mini-project involving development of a framework for proxy servers. The objective of this project is to develop a framework for creating proxy servers. After analyzing several different proxy servers, our group found HTTP/TCP port-forwarding the most interesting kind of proxy application for this project. For port-forwarding proxies, we were able to find enough resources in terms of Java code without existing frameworks and an understandable reusable design. We achieved the white-box framework in the first iteration by synthesizing abstract classes from the code. In the second iteration we converted the abstract classes into interfaces, resulting in a black-box framework. The third iteration required no modification of the framework and served as a validation of the black-box framework that was built at the end of the second iteration. This project helped us understand the steps involved in developing frameworks from existing reusable code and progressing from white-box to gray-box to black-box level. We were also able to extend our knowledge of design patterns by using patterns such as Factory, Singleton, Mediator, Adapter, Bridge and Observer. Fault tolerance techniques were applied to the code through recoverable exception handling and error checking. Abstract .......................................................................................................................................................... 1 Introduction ................................................................................................................................................... 3 Frameworks: ............................................................................................................................................. 3 Proxy Server: ............................................................................................................................................ 4 Proxy-Server-to-Proxy-Server Linking: Port-Forwarding Proxy servers ................................................ 5 Design Patterns ......................................................................................................................................... 7 Fault-tolerance: ........................................................................................................................................ 7 Original Port-forwarding proxies ................................................................................................................. 9 ProxyServerJ Proxy application ............................................................................................................. 9 TCP Reflector Proxy application .......................................................................................................... 10 Dodgy TCP Port forwarding proxy ...................................................................................................... 11 Frameworks and their UML diagrams ....................................................................................................... 12 Development of Framework 1 ............................................................................................................... 12 Development of Framework 2 ............................................................................................................... 13 Development of Framework 3: .............................................................................................................. 15 UML Diagrams for applications with their frameworks: ........................................................................... 16 Conclusion ................................................................................................................................................... 22 Sources of the original proxy code .............................................................................................................. 23 Introduction Our goal was to create a framework that would enable reuse of domain-specific design and code for proxy servers. Three port-forwarding proxy servers were chosen and the entire development involved three iterations, going progressively from white-box to black-box framework. We also applied design patterns and fault-tolerance techniques to our frameworks. This document also contains the Unified Modeling Language (UML) diagrams from each stage of development. Frameworks: A framework is a set of classes that embodies an abstract design for solutions to a family of related domain-specific problems and supports reuse at a larger level of granularity than classes. Frameworks allow a collection of objects to serve as a template solution or a semi-complete application. The application specific logic “plugs” into the framework through a set of interfaces. A framework provides inversion of control, implying that the framework calls the application specific code. Frameworks are ideally suited for capturing the common features in a product family. The abstraction is at such a high level that bulk of the functionality is captured in the framework and each application is an extension of the framework. A framework provides a reusable architecture for a family of applications from a particular domain. With frameworks, the principle of reuse is applied to whole applications or sub-systems, so that the effort required to develop a new application is limited to the difference in functionality between the particular application and the rest of the family. A good framework captures a good underlying design and it can reduce the cost of developing an application by an order of magnitude because it lets you reuse both design and code. However, developing a good framework could be expensive. Hence a framework must be simple enough to be learned and yet must provide enough features so that it can be used quickly. Frameworks evolve from "white-box" to "black-box." An intermediate stage between the two is referred to as the gray-box framework. A white-box framework permits creation of new classes by changing the abstract classes that form the core of the framework. A thorough understanding of the hierarchical structure and source code is important for implementing application specific logic with a white-box framework. A black-box framework permits plugging in the application specific logic that confirms to the pre-defined interface or protocol. The application specific logic does not change the framework and it does not make any new concrete subclasses to utilize the framework. The gray-box framework is between the two extremes. To use a gray-box framework, new concrete sub-classes must be defined and used to build the application. The subclasses are rightly coupled to super-classes and the sub-classes must meet the interface specified by the superclasses. The programmer must understand the framework’s interfaces in detail. Initial framework designs may be acceptable for single applications. However, the ability to generalize for a family of applications can only come by actually building the applications and determining which abstractions are being reused across the applications. Generalizing from a single application rarely happens. This is the reason we could achieve only a white-box framework in the first iteration. It is much easier to generalize from two applications, but it is still difficult. Provided that all of the applications fall within the problem domain, common abstractions will become apparent in a few iterations. We were able to extract common functionalities from the first two applications and define a tentative standard interface for port-forwarding proxies. Fortunately, the third port-forwarding proxy server application had features very similar to the first two applications. Thus the third iteration validated our interface, leading to the success of our black-box framework for the given set of three applications. A framework can be expected to evolve, especially if the application domain is not as specific as “port-forwarding proxy servers”. If the problem domain has an infinite horizon, the framework development might continue to evolve until all potential applications have been analyzed and their features incorporated into the framework. Proxy Server: A proxy server is a specialized server that listens for requests from clients and forwards these requests to remote Internet servers. The proxy server reads responses from the external servers and then sends them to internal clients. Clients using a proxy server feel as if they are getting responses directly from remote servers. For a client application (such as a browser) to use a proxy server, it must channel Internet requests through the proxy server. Most browsers allow configuration, so that they direct requests through a proxy server. Depending on the browser, you can identify a proxy server by identifying the server’s domain name or IP address. However, browsers must be individually configured on the subnet to look for the proxy server and send their requests to it. The proxy server acts as both a server system and a client system. It is a server when accepting HTTP requests from browsers and it acts as a client system when the browser connects to remote servers to retrieve documents. Proxy-Server-to-Proxy-Server Linking: Port-Forwarding Proxy servers Chaining proxy servers provides an extra level of indirection and is particularly applicable when groups of clients need to be configured as per different policies. This involves setting up an outer level proxy that connects directly to the Internet and several inner level proxies that form the link between the clients and the outer-level proxy. Any access restrictions set for the external (organizational) proxy server take precedence over access restrictions set for the internal (departmental) proxy servers. Port forwarding works by creating a proxy server for a source port that a TCP service uses. The proxy server waits on the local machine for a connection from a client program to the source port. Design Patterns Design patterns systematically names, motivates and explains a general design that addresses a recurring design problem in object-oriented systems. It describes the problem, the solution, when to apply the solution, and its consequences. It also gives implementation hints and examples. The solution is a general arrangement of objects and classes that solve the problem. The solution is customized and implemented to solve the problem in a particular context. We implemented a few of the design patterns – Factory Method: Defines and interface for creating an object, but let subclasses decide which class to instantiate. The Factory Method lets a class defer instantiation to subclasses. Singleton: Ensures that a class has only one instance and it provides a global point of access to it. Adapter: Converts the interface of a class into another interface that clients expect. It lets the classes work together that couldn’t otherwise because of incompatible interfaces. Bridge: It decouples the abstraction from its implementation so that the two can vary independently. Mediator: It defines an object that encapsulates how a set of objects interacts. It promotes loose coupling by keeping objects from referring to each other explicitly and it lets you vary their interaction independently. Observer: It defines a one-to-many dependency between objects so that when one object changes its state, all its dependents are notified and updated automatically. Fault-tolerance: A fault is defined as a condition that might lead to a failure. Failure is a malfunction in the system. An error is an incorrect or undesired response from the system that indicates a fault is present. Fault tolerance involves fault detection, confinement, diagnosis and recovery. The third framework and any plugged proxy application have been made fault-tolerant to the level of minimal performance. Faults in the system are enclosed within exception handling code that detects and recovers from errors, thereby preventing the system from complete failure. The proxy applications are all port-forwarding, but the client applications such as browsers may request documents through different protocols such as HTTP, FTP, telnet, etc that connect through different ports. The framework takes care of wrong port numbers and restricts the proxy applications to the desired operation. UML Diagrams The Unified Modeling Language (UML) defines a set of diagrams that represent different aspects of the software system under design. The UML notation is defined for both static and dynamic views of the system. A Class diagrams is a collection of static declarative model elements that represent the objectoriented classes and the relationships (such as associations, generalizations and aggregations) between the classes. Original Port-forwarding proxies ProxyServerJ Proxy application This is a Java based HTTP proxy server. It allows multiple users to share single Internet connection. It performs generic port forwarding to another server. UML diagram for ProxyServerJ application The proxy saves the current configuration to a disk file, so it does not have to request the user to re-enter the data on the next run. We analyzed the classes in this application and found it suited to our requirement. We started work on our first proxy by identifying the common operation shown by this proxy application. To run this proxy, we need to provide the hostname, the remote port and the local port. The proxy application provides a graphical user interface to accept the configuration from the user. It saves this configuration to the persistent storage so the user does not require to re-enter the configuration information on each run. In short, this application has a user-oriented interface design. TCP Reflector Proxy application A multithreaded java class that allows you to redirect all connections to a particular machine and port to another machine and port. UML diagram for TCP Reflector proxy application This proxy application is used to talk to a socket not located on the host from which it is served. The TCPReflector must be run on a known port and it must be set up to connect the host and port required by the application. The TCPReflector will behave as if the application has a direct connection to that remote host and port. This proxy requires the user to provide the local and remote port numbers and the host IP address on the command line as switches. It is capable of accepting a few more advanced parameters, but can work with the minimal switches such as –port and –server. Dodgy TCP Port forwarding proxy This is a port forwarding proxy that works at the TCP level. It forwards the data to the external proxy over the same TCP connection. The original proxy does not work correctly with Windows 95 systems. The forwarded telnet or ssh sessions will just lock up randomly, although the underlying session is actually still open. The terminal just stops redrawing. UML diagram for Dodgy TCP port-forwarding proxy This proxy application requires the user to provide the local and remote port information on the command line. However the application relies on the sequence of the command line parameters rather than switches. Frameworks and their UML diagrams Development of Framework 1 This is a white box framework. The application class inherits from the FWProxy, which is an abstract class providing a skeleton implementation of a proxy. The application needs to provide two things - the configuration information and the connection handler. The configuration information is obtained using a graphical user interface for the first proxy application called ProxyServerJ. The user provides the configuration. The proxy provides a base connection handler that can be used by the application. We extracted the common classes, the server classes and the connection handling classes from the original proxy application and incorporated them into the set of abstract classes forming the framework. The application is responsible for collecting the connection information. UML diagram for Framework 1 (whitebox) Development of Framework 2 This is a black box framework and unlike Framework 1, this one uses interfaces. We derived most of the interfaces after analyzing the TCP reflector proxy. This is because TCP reflector provides a better implementation of the connection handling and proxy server than the previous application. UML diagram for Framework 2 (blackbox) The FWProxy contains an implementation of the Mediator design pattern since it encapsulates how the set of applications interact. It promotes loose coupling certain components of the framework interface and lets the interaction of the proxies vary independent of each other. FWProxy also provides a Factory design pattern that automatically identifies the application proxy in the current folder and instantiates the corresponding object. The proxy uses reflection mechanism to find out which class corresponding to the application uses the FWProxyInterface. This is necessary to keep the main function within the framework, which is one of the important properties of the framework. This is an implementation similar to the Adapter design pattern because it lets classes having different interfaces to work with the framework. Any proxy application being used by this framework needs to know two interfaces to make use of this framework. These interfaces are FWProxyInterface and FWConnectionMonitorInterface. This set of two interfaces are implemented using the Bridge design pattern. It decouples the abstraction from its implementation so that the two can vary independently. FWProxyInterface is used to provide the proxy with information such as the connection configuration and FWConnectionMonitorInterface is used to receive and send events. Implementing the FWConnectionMonitorInterface is optional. The application may choose to implement this interface if it is required to perform tasks such as opening a connection, cleaning a connection and closing the connection. The FWConfig class contains the proxy configuration. This class implements the Singleton design pattern. Part of the configuration such as the localhost, port and server information is provided by the application. FWAgent handles the data transfer from the client to the server and from the server to the client. Each of these agents is an independent thread. Whenever the connection is terminated, the FWAgent informs the corresponding FWProxyServer which closes the socket and stream. FWAgent contains an implementation of the Observer design pattern. It defines a dependency so that when one object changes state, it notifies the dependents automatically. Development of Framework 3: This is also a black-box framework with very little change from the second framework. UML diagram for Framework 3 (blackbox) Additional fault tolerance techniques have been implemented. It involves a few load-balancing features. It also prints the usage information and error messages. This framework prevents the proxies from disrupting the working of the system and provides recoverable error checking so that the system can continue to work with degraded level of service. UML Diagrams for applications with their frameworks: UML Diagram for ProxyServerJ application with Framework 1 (white-box) We found that the first iteration consumed a lot of resources. It involved extracting what looked like the universal features of the application domain and gathering these features in an abstraction. The second stage required lesser time than the first and the third iteration required very little time. We came to the conclusion that frameworks should be developed only when many applications are going to be developed within a specific problem domain, allowing the time savings of reuse to recover the time invested to develop them. UML Diagram for ProxyServerJ application with Framework 2 (black-box) UML Diagram for TCP Reflector proxy application with Framework 2 (black-box) UML Diagram for ProxyServerJ application with Framework 3 (black-box framework with fault-tolerance features) UML Diagram for TCPReflector application with Framework 3 (black-box framework with fault-tolerance features) UML Diagram for Dodgy TCP port-forwarding proxy application with Framework 3 (black-box framework with fault-tolerance features) Conclusion We found that the first iteration consumed a lot of resources. It involved extracting what looked like the universal features of the application domain and gathering these features in an abstraction. The second stage required lesser time than the first and the third iteration required very little time. We came to the conclusion that frameworks should be developed only when many applications are going to be developed within a specific problem domain, allowing the time-saving from reuse to recover the time invested to develop them. We also realized that the current black-box framework might not suit some other proxy implementations. Hence this framework must be flexible enough to accommodate more proxies. We provided hooks within our framework for future extensions. This project also helped us understand a few more design patterns not done as part of the class exercises. We incorporated fault-tolerance and recoverable exception handling into our final framework. Sources of the original proxy code ProxyServerJ proxy code http://members.home.net/vladimirl/ProxyServerJ.html TCP Reflector proxy code http://208.223.9.21/jfd/java/tcp/tcp/html Dodgy TCP port-forwarding proxy code http://www.mooh.org/public/proxy