1. Background
In today’s websites, there are more and more access channels, and the technology is becoming more and more advanced, such as WAP, SMS, EMAIL, traditional Web, Socket, etc. If even databases and LDAP are included, access If so, the space that needs to be expanded in the design must be very good to ensure that when adding new channels, no more code modifications or even code changes are required. But is it possible? I don’t think it is possible, but is there any way to better solve the perfection of this multi-channel access framework?
2. Architecture
[Figure 1]
As shown in Figure 1, when all the existing accesses have been used, designers are dazzled. If it is to gather people, then these programs can be written in any way, and it will definitely work. It can be implemented, but it will be more painful to maintain. Let’s go back to the question, how can we achieve a more perfect implementation? Figure 2 shows:
[Figure 2]
Figure 2 looks like an octopus with eight claws. The octopus legs are connected to all access channels respectively. The core of connecting all these channels is the XMLRouter, the head of the octopus. The role of the Router here is to communicate with all channels and realize The benefits of data routing and improving the scalability and flexibility of the system architecture will be many. It is called XMLRouter because if XML, a flexible and standardized language, is not used as a data transmission medium, the workload of the Router will also increase exponentially. Defining the XML specification will bring about future expansion. Comes with many benefits.
3. Ideas and Patterns
The original idea of XMLRouter came from the computer’s motherboard and <
>In the Builder Pattern, the PCI slot of the computer motherboard defines the PCI specification. As long as the card you produce meets the PCI standard, it can work when you insert it into the motherboard. As for how it works inside, it has been packaged. . Builder Pattern proposes to separate complex construction and implement it step by step. XMLRouter separates these complex channels and performs them one by one.
Services idea: In order to communicate with Router, in these A unified interface must be defined when accessing the channel, here it is called Services. As long as the program conforms to the Services specification, it can access the Router and route data.
Factory mode and Composite mode
XMLRouter will be generated using the Factory mode in the actual design. Router Produced by RouterFactory, it will be placed in the queue when it is put into use. The transmission data, receiving data and return data are all called from the corresponding Router from the queue, and the Composite mode is applied.
4. XML configuration file
XML file for Router The use is divided into two parts. The first is the configuration of the Router, such as:
Here is a quote: <?xml version="1.0" ?> <services> <!-- database Service --> <service name="database" type="database" class="com.web.service.DBService"> <connector driver="com.microsoft.jdbc.sqlserver.SQLServerDriver" url="jdbc:microsoft:sqlserver://192.168.0.179:1433" user="test" passwd="test" /> </service> <!-- Web Service--> <service name="web" type="web" class="com.web.service.WebService" > <connector /> </service> … </services> |
This is the configuration file of the Router. The service node represents the channel that needs to be accessed. The service node contains the connector sub-node. The configuration of the sub-node is distinguished by type. If it is a database, it contains attributes such as url, user, passwd, driver and so on. , if it is a socket, it contains attributes such as port and maxthread. The attribute values can be configured according to your own definition.
Another type of XML file is the XML transaction data file, which is used to transfer data in all services. Each Service contains its own The corresponding XML file, such as webtrans.xml, has the following format:
Here is a quote: <?xml version="1.0" ?> <transaction> <trans name="addDoc" service="database" method="insert"> <property name="createtime" type="timestamp"/> <property name="creatorid" type="long"/> <property name="doctypeid" type="int"/> <property name="docstatusid" type="int"/> </trans> </transaction> |
The corresponding dbtrans.xml format is as follows
Here is a quote: <trans name="addDoc" table="TDOC_DOCS" method="insert"> <primarykey name="docid" /> <set> <property name="createtime" type="timestamp"/> <property name="creatorid" type="long"/> <property name="doctypeid" type="int"/> <property name="docstatusid" type="int"/> </set> </trans> |
The rest of the XML can be customized according to such rules
. 5. Technical implementation
of RouterFactory
Here is a quote: package com.web.router; import com.web.platform.Exception.RouterException; import java.util.java/util/Hashtable.java.html" target="_blank">Hashtable; |
The following is a reference fragment: /** * Classes generated and cleared by Router */ public class RouterFactory { /** * Tree front stored by Router */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueuePairFront = null; /** * Tree back stored by Router */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueuePairBack = null; /** * Tree stored by Router */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueueRouter = null; /** * Returned XMLRouter */ public static XMLRouter instance = null; /** *Definition of Router */ public static RouterDefine routerdefine = null; /** * Router ID number */ public static long routeIndex = 0; /** * @roseuid 3F169C21027C */ public RouterFactory() { } /** * Initialize Hashtable and Vector */ public static void initFactory() throws java/lang/Exception.java.html" target="_blank">Exception { QueuePairFront = new java/util/Hashtable.java.html" target="_blank">Hashtable(); QueuePairBack = new java/util/Hashtable.java.html" target="_blank">Hashtable(); QueueRouter = new java/util/Hashtable.java.html" target="_blank">Hashtable(); initRouteDefine(); } /** * Initialize Route settings * */ private static void initRouteDefine() throws java/lang/Exception.java.html" target="_blank">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 java/lang/Long.java.html" target="_blank">Long(index)); } /** * Generate an instance of XMLRouter * @return com.web.router.XMLRouter * @roseuid 3F1618A103BC */ public static XMLRouter popInstance() throws RouterException { routeIndex++; instance = new XMLRouter(routeIndex); setDefine( instance ); QueueRouter.put(new java/lang/Long.java.html" target="_blank">Long(routeIndex), instance); return instance; } /** * Clear Hashtable, Vector, etc. * @roseuid 3F1618B203C1 */ private static void freeResource() throws java/lang/Exception.java.html" target="_blank">Exception { QueuePairFront.clear(); QueuePairBack.clear(); QueueRouter.clear(); QueuePairFront = QueuePairBack = QueueRouter = null; } /** * Clear instance * @param instanceID * @throwsException */ public static void removeInstance(XMLRouter instance) throws java/lang/Exception.java.html" target="_blank">Exception { instance.clear(); QueueRouter.remove( new java/lang/Long.java.html" target="_blank">Long(instance.getIndex() ) ) ; } /** * Method isNull. * @return boolean */ public static boolean isNull() { … return false; } } |
Here is a quote: package com.web.router; import com.web.platform.Exception.RouterException; import com.web.common.*; import java.util.*; import java.lang.reflect.java/lang/reflect/Method.java.html" target="_blank">Method; import java.lang.reflect.java/lang/reflect/Constructor.java.html" target="_blank">Constructor; /** * @author keli * @version 0.0.1 * The key to the platform, the routing class, each Router will read from RouterFactory * The tree front, back, routeIndex stored by Router is for the purpose of routing * The applied objects can be cleared later. * Router can implement synchronous and asynchronous functions. */ public class XMLRouter { /** * Tree front stored by Router */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueuePairFront = null; /** * Tree back stored by Router */ private static java/util/Hashtable.java.html" target="_blank">Hashtable QueuePairBack = null; /** * The index number of this router */ private long routeIndex = 0; /** * Router settings */ private RouterDefine define = null; /** * Used to determine the starting point of the route */ private java/lang/String.java.html" target="_blank">String action = ""; /** *This variable is only used to apply for a new class in the routeto method */ private java/lang/String.java.html" target="_blank">String classname = ""; /** */ public XMLRouter(long index) { routeIndex = index; } /** * Routing * @throws Exception * @roseuid 3F1616BD0186 */ public void routing(Env env) throws RouterException, java/lang/Exception.java.html" target="_blank">Exception { /*If it is the starting point*/ if( action.equalsIgnoreCase( RouterConstant.CFG_FUNC_ROUTETO ) ) { … } /*If it is a return point*/ else if( action.equalsIgnoreCase( RouterConstant.CFG_FUNC_ROUTEBACK ) ) { … } /*Otherwise it is an error*/ else throw new RouterException("Set Router action error."); } /** * Read the ID number of this Router. * @return long */ public long getIndex() { return routeIndex; } /** * Clear all objects. * @throws RouterException */ public void clear() throws RouterException { QueuePairFront.remove(new java/lang/Long.java.html" target="_blank">Long(routeIndex)); QueuePairBack.remove(new java/lang/Long.java.html" target="_blank">Long(routeIndex)); /*System recycling*/ java/lang/System.java.html" target="_blank">System.runFinalization(); } /** * Set the settings of 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( java/lang/String.java.html" target="_blank">String actionName ) { action = actionName; } } |
Service class
Here is a quote: package com.web.common; import com.web.platform.Exception.RouterException; /** * The parent class of Service, abstract */ public abstract class RouteService { /** */ publicRouteService() { } /** * routeTo method is the starting point of the transaction. * @param env * @throws RouterException */ public abstract void routeto(Env env) throws RouterException; /** *routeBack, the end point of the transaction, * @param env * @throws RouterException */ public abstract void routeback(Env env) throws RouterException; /** * The routeaccept method is the receiving point of the transaction and the receiving function of routeto. * routeaccept is the main processing function of passive transaction objects * @param env * @throws RouterException */ public abstract void routeaccept(Env env) throws RouterException; /** * The routing method is the external interface function of Service * @throws RouterException */ public abstract void routing() throws RouterException; |
Next, you need to implement all Services classes, which will not be introduced here.
6. Explain that
this Router can only implement synchronous transactions so far, and does not support asynchronous transactions for the time being. However, since the Router is designed using the Composite model, the implementation of asynchronous transactions can also be expanded, so detailed analysis will not be done here.