O O D B Design And Implementation - Part 3 -

Joe

Thành viên VIP
21/1/13
2,690
1,244
113
Hi

(cont. of Part 2)

ODB Infrastructure on the Client site
The most optimal Database design is the Client/Server (C/S) design. Herein the clients are physically "segregated" from the direct accessing to the DBs which are under control of a DB server. This architectural feature guarantees the independency of DB from any direct manipulation carried by the clients -intended or unintended. And the Clients are immune against any kind of problems on the server site. Both sites are happy and stay independent from each other's problems.

Nevertheless the Clients must be somehow qualified for some certain activities such as Delete/Update/Create/etc. Authentication with Password and UserID is the most popular and the most reliable technique in a C/S environment. We don't try to complicate the matter (Kalashnikov Principle), but work with this "tested" technology: Password-UserID. So, the first infrastructure on the Client site is the User-Creditability which is in form of:
  • Read. The basic right (0). The lowest privilege. Users with this privilege can only view (READ) the objects.
  • Write (or update). The next higher level (1). Users with 1-privilege can not only view, but also modify (UPDATE) the objects.
  • Delete (and Create). The highest level (2) or the highest privilege for a user. With this privilege (s)he has all the rights: view, modify and remove (DELETE) objects. DELETE means also CREATE. If a user with this privilege opens an ODB (file) which is nonexistent ODManager will create an empty ODB on his/her local ODB Server.
The 3 basic rights are the principle activities for an ODB-API for the clients. And we have to provide this ODB infrastructure on the client site. Beside the 3 types of privilege for the users UserList must provide a Superuser privilege for the maintenance tasks on the ODB Server site. In case of problems (e.g. loss/oblivion of Superuser Password or ID) UserList must be able to recreate a new UserList with the default Superuser with the Password system and the ID admin (both are case sensitive) and the facility to recover the rest of the users of the "old" UserList. However, this default Superuser cannot access the ODB. How? I'll explain the implementation in the next section.
  1. An authentication process that works on both sites (Client-Server) and provides the clients these basic rights (0, 1 and 2).
  2. An API that allows the Client-App to plug-in and to work with the desired ODB on the server site.
In the previous sections we've learned that OO Data and Object are inseparable. That requires an existence of all working objects on the Client site. And they are the JAVA classes. The OO Data are on the Server site, their "shuck" (or class) is on the Client site. Due to following reasons why JAVA classes shouldn't be included in ODB:
  • they could include some inner classes,
  • they are parts of an external or internal package,
  • they must be known during the compiling phase. Casting during the runtime requires also their explicite existence,
  • reflection could lead to security leaks (access to private fields or methods).
And developers who created the apps usually possess the compiled classes before the apps were packaged and distributed to the users (clients).

The following UserList API that works on both sites should provide the following basic methods (YOU should try to implement this UserList):
PHP:
Package joodb
Class UserList

    Object joodb.UserList

    public class UserList extends Object

    Constructors Constructor     Description

    UserList(String file)        Contructor.

    Modifier/Type      Method                                         Description

    boolean            addUser(String pw, String uid, int right)      add new User
    boolean            deleteUser(String uid)                         delete User
    ArrayList<String>  getUserList(String pw, String uid)             getUserList a list of all Users.
    int                getUserPrivilege(String pw, String uid)        getUserPrivilege()
    boolean            isSuperuser(String pw, String uid)             isSuperuser
    boolean            isUser(String pw, String uid)                  isUser
    void               recover(String path)                           recover Userlist. recover a Userlist with the default Superuser PW:system, ID:admin
    void               save()                                         Save userlist in the give path (see Constructor)
    boolean            updateUser(String uid, String pwOLD, String pwNEW) update User Password
                                                                      (used by users to change their PW)
    boolean            upgradeUserPrivileg(String suPW, String suID,  upgrade User Privilege (used by Superuser)
                                           String uid, int newPriv)
The UserList API is naturally maintained and kept on the Server site. I show the UserList here because of the user or client's right on the Client site.

Note: for the ease of use (Kalashnikov) the UserList must be "pegged" on a fixed name without suffix. In my implementation it's the name "userlist". The storing of user data must be encrypted, too. Encryption/Decryption is only "foolproof" if the encrypting/decrypting technique is known only by YOU yourself. Otherwise it's the question of time that your technique will be broken. In the Source-bundle you won't find the source EnDecrypt.java. But a dummy EnDecrypt.java and you have to develop the two declared methods on your own.
PHP:
public class EnDecrypt {
  /**
    decrypt an encrypted String
    @param inp String to be encrypted
    @param ext boolean, true for Extended encrypting (used for Networking), false for local UserList
    @return decrypted String (null if invalid inp)
  */
  public static String decrypt(String inp, boolean ext) {
    return inp;
  }
  /**
    decrypt() a String
    @param inp String to be decrypted
    @param ext boolean, true for Extended encrypting (used for Networking), false for local UserList
    @return encrypted String (null if invalid inp)
  */
  public static String encrypt(String inp, boolean ext) {
    return inp;
  }
}
The most important part for a functional infrastructure on the Client-Site is the "Plug-In API". Like SQL for RDB Client Applications can only access the ODB via this "Plug-in API". The 3-basic access rights (read/update/delete) are the bases for the implementation. Because we are dealing with the C/S architecture the Plug-In API is here also the (network) communication API.

Network communication is complex and variable. In the past Networking-Communication is the bottleneck. Even in the 90s a "leased line" with 64 K-bps is an expensive wonder. Today we deal with GB-bps over a public fiber optical line and none of us is aware about it. But some of us become fat (or obese) with demands (more video streaming, more hifi music, more colorful images, etc.) and run into troubles with the "response time". And the networking technology runs pantingly after our demands. Some of us, old codgers, still work with "Socket" while SocketChannel is available since years. What is the difference between Socket and SocketChannel, anyway?

As I've already mentioned about the "expensive wonder of 64 Kbps" Socket is the replacement of TTY which stands for "teletypewriter". A Technology of Alexamder Bell's
epoch. A bit-wise communication. And this technique still mints the communication of today: bit-wise. Socket works bit-wise, too.


(source: Oracle)

Further, modern networking still bases on the "age-old US military designed TCP/IP" as memory was as precious as gold: the max buffering was (and still is) 32768 bytes. Meager, isn't it? SUN, swallowed by Oracle, implemented the so-called "New IO (nio)" technology in order to overcome the sluggish bitwise communication. There are FileChannel and SocketChannel. Both work block-wise as the computer today does: in block of 4KB (Windows or Linux). It's obvious that blockwise is faster than bitwise (or bytewise). You want some evidences? Well, let check the source of InputStream and OutputStream (the IO of Socket):
PHP:
// InputStream
    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }
//--------------------------------------------------------------------------
// OutputStream
    public void write(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if ((off < 0) || (off > b.length) || (len < 0) ||
                   ((off + len) > b.length) || ((off + len) < 0)) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return;
        }
        for (int i = 0 ; i < len ; i++) {
            write(b[off + i]);
        }
    }
Both Read and Write work bitwise. Let verify the SocketChannel
PHP:
    public abstract int read(ByteBuffer dst) throws IOException;

    public abstract long write(ByteBuffer src) throws IOException;
Both Read and Write are abstract and must be implemented depending on the underlying hardware. And ByteBuffer? It's the new basic Buffering block of NIO.

Our next implementation for the Client infrastructure is the Networking API that bases on SocketChannel. Try to implement this API. The requirements are:
PHP:
Package joodb
Class ODBConnect

    Object
        joodb.ODBConnect

    public class ODBConnect extends Object

    Object Data Connect

        Constructor Summary
        Constructors Constructor                                                  Description
        ODBConnect()                                                              Empty contructor
        ODBConnect(String dbHost, int port, String pw, String uID)                contructor

        Method Summary
        Modifier and Type      Method                                             Description
        void                   add(String dbName, String key, byte[] obj)         add object
        void                   add(String dbName, String key, Object obj)         add object
        void                   close(String dbName)                               close.
        boolean                commit(String dbName)                              commit
        boolean                commit(String dbName, String key)                  commit
        void                   connect(String dbName)                             connect to ODB Server
        void                   delete(String dbName, String key)                  delete object
        void                   disconnect()                                       disconnect the connection to OODB Server and closes all opened DBs
        byte[]                 getByteArray(String dbName, String key)            getBytes byte array (of object)
        ArrayList<String>      getClusterKeys(String dbName, String node)         getClusterKeys returns cluster keys of dbName
        String                 getID()                                            getID of this connection
        ArrayList<String>      getKeys(String dbName)                             getKeys returns all keys of dbName
        ArrayList<String>      getLocalKeys(String dbName)                        getLocalKeys returns local keys of dbName

        protected joodb.ODBResult getResult(String dbName, ByteArrayOutputStream bao)
        boolean                isExisted(String dbName, String key)              isExisted
        boolean                isLocked(String dbName, String key)               isLocked
        boolean                lock(String dbName, String key)                   lock key.
        protected void         panicShutdown()
        Object                 read(String dbName, String key)                   read object
        boolean                rollback(String dbName)                           rollback ALL modified objects
        boolean                rollback(String dbName, String key)               rollback
        void                   save(String dbName)                               save.
        protected joodb.ODBResult send(String dbName, String cmd, String key)
        protected joodb.ODBResult send(String dbName, String cmd, String key, Object obj)
        boolean                transAction(String dbName, String action, String key, Object object)  transAction starts a Transaction and completes a commit if nothing happened in-between
        boolean                unlock(String dbName)                            unlock all locked keys of this dbName
        boolean                unlock(String dbName, String key)                unlock key
        void                   update(String dbName, String key, byte[] obj)    update object
        void                   update(String dbName, String key, Object obj)    update object
The Constructor ODBConnect(String dbHost, int port, String pw, String uID) contains ONE sensitive field: the Password. Therefore the mentioned EnDecrypt.java is involved with the boolean variable ext which is set to the value true.

OO data can be "big". Very big. To relieve the traffic on the net we should use the proven technology which works splendidly with the HTTP/HTTPS. It's the GZIP technology. OO Data are "gzipped" before they can be put on the net.

The basic ODBConnect API will serve as the base for further extensions. We are dealing with a very precarious approach: the load-balancing between Client and Server. The question is "where should the load be carried?" On the Server site or on the Client site? I decided to put the post-processing part on the Client site. Two reasons:
  • ODB Server has to serve numerous clients. So, it shouldn't be forced to do some post-processing works for its clients. And that could severely degrade the performance of ODB Server.
  • Client computer is nowaday quite powerful, and the (web)net is fast enough to transfer (all) the needed OO Data for the post-processing such as Data Mining. And that reduces considerably the load on the Server site.
I provide an API ODBMining for the Client site as an example so that YOU (or the licencees) could take it as a pattern to develop your own API for data mining purposes.
PHP:
Package joodb
Class ODBMining

  Object
    joodb.ODBConnect
      joodb.ODBMining


  public class ODBMining extends joodb.ODBConnect

    Constructor                                                    Description
    ODBMining(String dbHost, int port, String pw, String uID)      Contructor, open a connection to ODB-Server

    Modifier and Type   Method                                     Description
    ArrayList<Object>   allObjects(String dbName)                  allObjects of the specified ODB.
    ArrayList<Object>   allObjects(String dbName, String clsName)  allObjects.
    String              getClassName(String dbName, String key)    getClassName.
    ArrayList<String>   getFieldNames(String dbName, Class<?> cls) getFieldNames.
    ArrayList<String>   getFieldNames(String dbName, Object obj)   getFieldNames.
    ArrayList<String>   getFieldNames(String dbName, String key)   getFieldNames.
    ArrayList<Object>   selectAll(String dbName, String pat)       SelectAll.
    ArrayList<Object>   selectAll(String dbName, String comp, double cVal) select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "EQ", 123.456);
    ArrayList<Object>   selectAll(String dbName, String comp, float cVal) select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "EQ", 123.456f);
    ArrayList<Object>    selectAll(String dbName, String comp, int cVal) select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "LE", 123);
    ArrayList<Object>    selectAll(String dbName, String comp, long cVal) select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "GT", 123456);
    ArrayList<Object>    selectAll(String dbName, String comp, short cVal) select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "EQ", 123);
    ArrayList<Object>    selectAll(String dbName, String vName, String pat) select all objects with a vName that matches the pattern.
    ArrayList<Object>    selectAll(String dbName, String vName, String comp, double cVal) Select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, salary, "EQ", 123.456);
    ArrayList<Object>    selectAll(String dbName, String vName, String comp, float cVal)  Select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "Salary", "EQ", 123.456);
    ArrayList<Object>    selectAll(String dbName, String vName, String comp, int cVal) Select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "age", "LT", 50);
    ArrayList<Object>    selectAll(String dbName, String vName, String comp, long cVal) Select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "Salary", "GE", 123456);
    ArrayList<Object>    selectAll(String dbName, String vName, String comp, short cVal)  Select all objects that match the criterion of value
                                                                   Example: selectAll(dbName, "age", "EQ", 50);
(Next:OODB Infrastructure on the Server site)
 
Sửa lần cuối: