### How to Use XML to Achieve a Multi-Channel Access Website Architecture
In fact, the main purpose of writing this article is to share a framework I applied during a project in Switzerland last year. However, I was a bit worried that my expression might not fully convey the ideas I used, so I hesitated for a while before finally deciding to write it. If it’s not good enough, I can always improve it later. Of course, I hope everyone will provide plenty of feedback.
---
### **1. Background**
In modern websites, the number of access channels is increasing rapidly, and technology is becoming more advanced. Channels like WAP, SMS, EMAIL, traditional Web, Socket, etc., are now common. If we consider databases and LDAP as access points as well, then designing an architecture with excellent scalability becomes crucial to ensure minimal or no code changes when adding new channels. But is it possible to achieve this? While it may not be entirely feasible, what methods can we use to better address the perfection of a multi-channel access framework?
---
### **2. Architecture**
As shown in Figure 1, when all existing access channels are already in use, the design can become overwhelming. If the goal is simply to cobble together a solution, these programs can be written in any way and will still work. However, maintaining such a system would be painful. So, how can we achieve a more perfect solution?
During our team's architectural discussions, I proposed the concept of routing, which was unanimously approved by everyone. As shown in Figure 2:
#### **Figure 2**
Figure 2 resembles an octopus, with each "leg" connecting to all access channels. The core connecting all these channels is the XMLRouter. The role of the Router is to communicate between all channels, enabling data routing and enhancing the system's architectural scalability and flexibility. This approach offers numerous benefits. We call it XMLRouter because if we don't use XML—a flexible and standardized language—as the medium for data transmission, the workload for the Router would increase significantly. Defining a clear XML standard will bring many advantages for future expansion.
---
### **3. Ideas and Patterns**
The initial idea for XMLRouter came from the motherboard of a computer and the Builder Pattern described in *Design Patterns*. A computer motherboard's PCI slot defines the PCI standard; as long as your card conforms to the PCI standard, it will work once inserted into the motherboard. How it works internally is already encapsulated. The Builder Pattern proposes separating complex constructions into manageable steps, implementing them one by one. Similarly, XMLRouter separates these complex channels and processes them individually.
#### **Service Concept**
To enable communication with the Router, a unified interface must be defined for all channels accessing the system. These interfaces are referred to as Services. Any program conforming to the Services standard can connect to the Router and perform data routing.
#### **Factory Pattern and Composite Pattern**
In the actual design of XMLRouter, the Factory Pattern is used to create the Router. The Router is produced by RouterFactory and placed in a queue during operation. Data transmission, reception, and return all involve fetching the appropriate Router from the queue. This design applies the Composite Pattern.
---
### **4. XML Configuration File**
XML files are used in two parts within the Router:
#### **(1) Router Configuration**
Here’s an example of the Router configuration file:
```xml
...
```
This is the Router configuration file. Each `service` node represents an access channel. The `service` node contains a `connector` sub-node, whose configuration depends on the `type`. For example, if the type is `database`, it includes attributes like `url`, `user`, `passwd`, and `driver`. If the type is `socket`, it might include attributes like `port` and `maxthread`. Attribute values can be customized based on your own definitions.
#### **(2) XML Transaction Data Files**
Another type of XML file is the XML transaction data file, used to pass data between all services. Each service contains its corresponding XML file. For example, the `webtrans.xml` format looks like this:
```xml
```
The corresponding `dbtrans.xml` format looks like this:
```xml
```
Other XML files can be customized according to similar rules.
**Note:** Please refer to my previous article:
*"Implementation of Using XML to Encapsulate Database Operation Statements."*
---
### **5. Technical Implementation**
#### **RouterFactory**
```java
package com.web.router;
import com.web.platform.Exception.RouterException;
import java.util.Hashtable;
/**
* Class for creating and clearing Routers
*/
public class RouterFactory {
/**
* Front storage tree for Routers
*/
private static Hashtable QueuePairFront = null;
/**
* Back storage tree for Routers
*/
private static Hashtable QueuePairBack = null;
/**
* Storage tree for Routers
*/
private static Hashtable QueueRouter = null;
/**
* Returned XMLRouter
*/
public static XMLRouter instance = null;
/**
* Router definition
*/
public static RouterDefine routerdefine = null;
/**
* Router ID
*/
public static long routeIndex = 0;
/**
* Constructor
*/
public RouterFactory() {}
/**
* Initialize Hashtable and Vector
*/
public static void initFactory() throws Exception {
QueuePairFront = new Hashtable();
QueuePairBack = new Hashtable();
QueueRouter = new Hashtable();
initRouteDefine();
}
/**
* Initialize Route settings
*/
private static void initRouteDefine() throws Exception {
if( routerdefine == null )
routerdefine = new RouterDefine();
routerdefine.loadRouterDef();
}
/**
* Return instance
* @return com.web.router.XMLRouter
*/
public static XMLRouter getInstance(long index) throws RouterException {
return (XMLRouter)QueueRouter.get(new Long(index));
}
/**
* Create an XMLRouter instance
* @return com.web.router.XMLRouter
*/
public static XMLRouter popInstance() throws RouterException {
routeIndex++;
instance = new XMLRouter(routeIndex);
setDefine(instance);
QueueRouter.put(new Long(routeIndex), instance);
return instance;
}
/**
* Clear Hashtable, Vector, etc.
*/
private static void freeResource() throws Exception {
QueuePairFront.clear();
QueuePairBack.clear();
QueueRouter.clear();
QueuePairFront = QueuePairBack = QueueRouter = null;
}
/**
* Remove instance
* @param instanceID
* @throws Exception
*/
public static void removeInstance(XMLRouter instance) throws Exception {
instance.clear();
QueueRouter.remove(new Long(instance.getIndex()));
}
/**
* Method isNull.
* @return boolean
*/
public static boolean isNull() {
// Implementation details omitted
return false;
}
}
```
#### **XMLRouter**
```java
package com.web.router;
import com.web.platform.Exception.RouterException;
import com.web.common.*;
import java.util.*;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
/**
* Key component of the platform, the routing class. Each Router will read from RouterFactory.
* Router stores front and back trees, along with routeIndex, to facilitate clearing objects after routing.
* Router can implement both synchronous and asynchronous functions.
*/
public class XMLRouter {
/**
* Front storage tree for Router
*/
private static Hashtable QueuePairFront = null;
/**
* Back storage tree for Router
*/
private static Hashtable QueuePairBack = null;
/**
* Index number of this Router
*/
private long routeIndex = 0;
/**
* Router settings
*/
private RouterDefine define = null;
/**
* Used to determine the start or return point of routing
*/
private String action = "";
/**
* Variable used to instantiate new classes in the routeto method
*/
private String classname = "";
/**
* Constructor
*/
public XMLRouter(long index) {
routeIndex = index;
}
/**
* Routing
* @throws Exception
*/
public void routing(Env env) throws RouterException, Exception {
/* If starting point */
if( action.equalsIgnoreCase(RouterConstant.CFG_FUNC_ROUTETO) ) {
// Implementation details omitted
}
/* If return point */
else if( action.equalsIgnoreCase(RouterConstant.CFG_FUNC_ROUTEBACK) ) {
// Implementation details omitted
}
/* Otherwise, error */
else
throw new RouterException("Set Router action error.");
}
/**
* Read the ID of this Router.
* @return long
*/
public long getIndex() {
return routeIndex;
}
/**
* Clear all objects.
* @throws RouterException
*/
public void clear() throws RouterException {
QueuePairFront.remove(new Long(routeIndex));
QueuePairBack.remove(new Long(routeIndex));
/* System cleanup */
System.runFinalization();
}
/**
* Set the configuration for this Router.
* @param def
* @throws RouterException
*/
public void setDefine(RouterDefine def) throws RouterException {
define = def;
}
/**
* Set the value of action
* @param actionName
* @throws RouterException
*/
public void setAction(String actionName) {
action = actionName;
}
}
```
#### **Service Class**
```java
package com.web.common;
import com.web.platform.Exception.RouterException;
/**
* Abstract parent class for Services
*/
public abstract class RouteService {
/**
* Constructor
*/
public RouteService() {}
/**
* routeto method, the starting point of transactions.
* @param env
* @throws RouterException
*/
public abstract void routeto(Env env) throws RouterException;
/**
* routeback, the endpoint of transactions.
* @param env
* @throws RouterException
*/
public abstract void routeback(Env env) throws RouterException;
/**
* routeaccept method, the receiving point of transactions.
* Also the receiving function for routeto.
* The main processing function for passive transaction objects.
* @param env
* @throws RouterException
*/
public abstract void routeaccept(Env env) throws RouterException;
/**
* routing method, the external interface function for Service.
* @throws RouterException
*/
public abstract void routing() throws RouterException;
}
```
Next, we need to implement all the Service classes, but I won’t go into detail here.
---
### **6. Notes**
...