Forum > Networking and Web Programming

N-tier multiuser application development

(1/5) > >>

JD:
I'm working on the development of a multiuser application using a 3 tier design - a rich client, an application server & a database backend. I have the following options:

a) Build everything in Lazarus

    Client: Lazarus Indy application
    Application Server: Custom Lazarus Indy application
    Database backend: Firebird/PostgreSQL

    The client side could use the TMemDataset to send streamed data using Indy TCP components to the application server which uses Zeos to communicate with the database. The problem is TMemDataset cannot handle master/detail relationships unlike the ClientDataset in Delphi. In addition, passing data over sockets can be blocked by firewalls on the client machine & in addition, sensitive data must be encrypted before sending it over the wire. Encrypting & then decrypting data may have a negative impact on application speed.

b) Build a hybrid solution (I)
    
    Client: A rich client based on Lazarus/Delphi
    Application Server: Apache Geronimo/Glassfish
    Database backend: Firebird/PostgreSQL/JavaDB (also called Apache Derby)
    Database server: Apache Server

    The client side will use Habari ActiveMQ Client to communicate with the application server. The problem is I've never used it before & I'm wondering about the ease of deployment of this solution. It however looks very promising & is one for the future.

c) Build a hybrid solution (II)

    Client: A rich ExtPascal client
    Application Server: Custom Lazarus application
    Database backend: Firebird/PostgreSQL
    Database server: Apache Server

    The client could use CGI or FastCGI to communicate with the application server. The problem here again is that I've never tried this before but ExtPascal (based on ExtJS) looks promising & is also likely to be one for the future.

I'm open to suggestions on the best way to approach this problem. I don't want to use a browser based client side because I don't think they are good at handling data displayed in grids. It is absolutely essential for me that the client resembles a normal desktop application but its inner workings make it a web application. I want the users to have a rich desktop experience.  :D

I know Lazarus does not have anything like DataSnap or WebSnap, so what can I use as alternatives? I've looked at the excellent FreeSpider component but like I said the grid displays are an issue for me.

I'll greatly appreciate your advice, links, articles etc.


jixian.yang:
Option A is appreciated.
Use Memorytable of Rxlib with source code modified, we can handle the modified, deleted and inserted data, like delta data in delphi.

With SSL support, Synapse and lNet are popular.

JD:

--- Quote from: jixian.yang on August 10, 2010, 06:39:06 pm ---Use Memorytable of Rxlib with source code modified, we can handle the modified, deleted and inserted data, like delta data in delphi.

--- End quote ---

I have RxLib but what does "use Memorytable of RxLib with source code modified..." mean? What source code was modified?

jixian.yang:
The modified code can handle old value and new value of record. If just handle the modified, deleted and inserted data, the override InternalOpen, etc can do, not need to modify source code.

The following is the change:

Comparing files RxMemDsEx.pas and RXMEMDS.PAS
***** RxMemDsEx.pas

unit RxMemDsEx;

{$IFNDEF LINUX}
{$I rxl\rx.inc}
{$ELSE}
{$I RXL/rx.inc}
{$ENDIF}

***** RXMEMDS.PAS

unit rxmemds;


{$I rx.inc}

*****

***** RxMemDsEx.pas

uses SysUtils, Classes, Controls, DB, dbutils;
***** RXMEMDS.PAS


uses SysUtils, Classes, Controls, DB, dbutils;
*****

***** RxMemDsEx.pas

{ TRxMemoryData}

***** RXMEMDS.PAS

{ TRxMemoryData }

*****

***** RxMemDsEx.pas

  TRxMemoryData= class(TDataSet)
  private
    FOldBuf:PChar;
    FOnFilterRecordEx: TFilterRecordEvent;
***** RXMEMDS.PAS

  TRxMemoryData = class(TDataSet)
  private
    FOnFilterRecordEx: TFilterRecordEvent;
*****

***** RxMemDsEx.pas
    procedure InternalDelete; override;
    procedure InternalEdit; override;
    procedure InternalPost; override;
***** RXMEMDS.PAS
    procedure InternalDelete; override;
    procedure InternalPost; override;
*****

***** RxMemDsEx.pas
    procedure InternalOpen; override;
    procedure InternalCancel; override;
    procedure OpenCursor(InfoQuery: Boolean); override;
***** RXMEMDS.PAS
    procedure InternalOpen; override;
    procedure OpenCursor(InfoQuery: Boolean); override;
*****

***** RxMemDsEx.pas

{ TRxMemoryData}

***** RXMEMDS.PAS

{ TRxMemoryData }

*****

***** RxMemDsEx.pas
  FRecords := TList.Create;
  FOldBuf := nil;
end;
***** RXMEMDS.PAS
  FRecords := TList.Create;
end;
*****

***** RxMemDsEx.pas

procedure TRxMemoryData.InternalEdit;
begin
     inherited InternalEdit;
     GetMem(FOldBuf,FRecBufSize);
     Move(ActiveBuffer^,FOldBuf^,FRecBufSize);
end;
***** RXMEMDS.PAS

{ Records Management }

function TRxMemoryData.GetCapacity: Integer;
begin
  if FRecords <> nil then Result := FRecords.Capacity
  else Result := 0;
end;
*****

***** RxMemDsEx.pas

{ Records Management }

function TRxMemoryData.GetCapacity: Integer;
begin
  if FRecords <> nil then Result := FRecords.Capacity
  else Result := 0;
end;
***** RXMEMDS.PAS

procedure TRxMemoryData.SetCapacity(Value: Integer);
begin
  if FRecords <> nil then FRecords.Capacity := Value;
end;
*****

***** RxMemDsEx.pas

procedure TRxMemoryData.SetCapacity(Value: Integer);
begin
  if FRecords <> nil then FRecords.Capacity := Value;
end;
***** RXMEMDS.PAS

function TRxMemoryData.AddRecord: TMemoryRecord;
begin
  Result := TMemoryRecord.Create(Self);
end;
*****

***** RxMemDsEx.pas

function TRxMemoryData.AddRecord: TMemoryRecord;
begin
  Result := TMemoryRecord.Create(Self);
end;

function TRxMemoryData.FindRecordID(ID: Integer): TMemoryRecord;
***** RXMEMDS.PAS

function TRxMemoryData.FindRecordID(ID: Integer): TMemoryRecord;
*****

***** RxMemDsEx.pas
    dsCalcFields: RecBuf := CalcBuffer;
    dsOldValue:
    begin
    if FOldBuf=nil then
    RecBuf:=ActiveBuffer
    else
    RecBuf:=FOldBuf;
    end;
    dsFilter: RecBuf := TempBuffer;
***** RXMEMDS.PAS
    dsCalcFields: RecBuf := CalcBuffer;
    dsFilter: RecBuf := TempBuffer;
*****

***** RxMemDsEx.pas
  SetMemoryRecordData(Buffer, Rec.Index);

  GetMem(FOldBuf,FRecBufSize);
  Move(ActiveBuffer^, FOldBuf^, FRecBufSize);
end;
***** RXMEMDS.PAS
  SetMemoryRecordData(Buffer, Rec.Index);
end;
*****

***** RxMemDsEx.pas
  end;
  FreeMem(FOldBuf);
  FOldBuf:=nil;
end;
***** RXMEMDS.PAS
  end;
end;
*****

***** RxMemDsEx.pas
//  OpenCursor(false);
  //           俞疣螯 镱耠?桉镳噔脲龛
{  Fields.Clear;
***** RXMEMDS.PAS
//  OpenCursor(false);
  //           俞疣螯 镱耠?桉镳噔脲龛
{  Fields.Clear;
*****

***** RxMemDsEx.pas

procedure TRxMemoryData.InternalCancel;
begin
     FreeMem(FOldBuf);
     FOldBuf:=nil;
     inherited InternalCancel;
end;
***** RXMEMDS.PAS

procedure TRxMemoryData.InternalHandleException;
begin
  Application.HandleException(Self);
end;
*****

***** RxMemDsEx.pas

procedure TRxMemoryData.InternalHandleException;
begin
  Application.HandleException(Self);
end;
***** RXMEMDS.PAS

procedure TRxMemoryData.InternalInitFieldDefs;
begin
end;
*****

***** RxMemDsEx.pas

procedure TRxMemoryData.InternalInitFieldDefs;
begin
end;
***** RXMEMDS.PAS

function TRxMemoryData.IsCursorOpen: Boolean;
begin
  Result := FActive;
end;
*****

***** RxMemDsEx.pas

function TRxMemoryData.IsCursorOpen: Boolean;
begin
  Result := FActive;
end;

{ Informational }
***** RXMEMDS.PAS

{ Informational }
*****

herux:
Go to Option
 D. Using http://wiki.freepascal.org/tiOPF, its support HTTP Proxy-Remote.

Navigation

[0] Message Index

[#] Next page

Go to full version