Sybase NNTP forums - End Of Life (EOL)

The NNTP forums from Sybase - forums.sybase.com - are now closed.

All new questions should be directed to the appropriate forum at the SAP Community Network (SCN).

Individual products have links to the respective forums on SCN, or you can go to SCN and search for your product in the search box (upper right corner) to find your specific developer center.

Segmentation fault in C++ objects causes EAS to abort

10 posts in General Discussion (old) Last posting was on 2000-02-26 15:16:34.0Z
Eyal Mishor Posted on 2000-02-17 16:39:04.0Z
Newsgroups: sybase.public.easerver
Date: Thu, 17 Feb 2000 18:39:04 +0200
From: Eyal Mishor <eyal_mi@zahav.net.il>
X-Mailer: Mozilla 4.06 [en] (Win95; U)
MIME-Version: 1.0
Subject: Segmentation fault in C++ objects causes EAS to abort
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Lines: 11
NNTP-Posting-Host: efratgw.icomverse.com 199.203.140.6
Message-ID: <347_38AC2428.E1F555A9@zahav.net.il>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:28497
Article PK: 160651

Hi all,
I hope someone can help me:
I tried to run Corba wrapped C++ objects in EAS, and the C++ object
caused a segmentation fault. Because this was in one of the EAS
threads, it caused it to abort!
Is it possible to configure EAS to run such objects in a seperate
process so that it won't be so easily disturbed by such an error?
Or is there another solution?

Thanks in Advance,
Eyal Mishor


Dave Wolf [Sybase] Posted on 2000-02-17 16:44:34.0Z
Newsgroups: sybase.public.easerver
From: "Dave Wolf [Sybase]" <dwolf@sybase.com>
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Date: Thu, 17 Feb 2000 11:44:34 -0500
Lines: 22
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 5.00.2314.1300
X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2314.1300
NNTP-Posting-Host: dwolf-nt.sybase.com 157.133.41.127
Message-ID: <347_MlxDFbWe$GA.149@forums.sybase.com>
References: <347_38AC2428.E1F555A9@zahav.net.il>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:28495
Article PK: 160649

Please contact technical support. Ive received another report of this, and
we would consider this a bug after review.

Dave Wolf
Internet Applications Division

Eyal Mishor <eyal_mi@zahav.net.il> wrote in message
news:38AC2428.E1F555A9@zahav.net.il...
> Hi all,
> I hope someone can help me:
> I tried to run Corba wrapped C++ objects in EAS, and the C++ object
> caused a segmentation fault. Because this was in one of the EAS
> threads, it caused it to abort!
> Is it possible to configure EAS to run such objects in a seperate
> process so that it won't be so easily disturbed by such an error?
> Or is there another solution?
>
> Thanks in Advance,
> Eyal Mishor
>


Eyal Mishor Posted on 2000-02-18 20:57:57.0Z
Newsgroups: sybase.public.easerver
Date: Fri, 18 Feb 2000 22:57:57 +0200
From: Eyal Mishor <eyal_mi@zahav.net.il>
X-Mailer: Mozilla 4.6 [en] (Win95; I)
X-Accept-Language: en
MIME-Version: 1.0
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Lines: 35
NNTP-Posting-Host: 192.115.51.126
Message-ID: <347_38ADB255.97560768@zahav.net.il>
References: <347_38AC2428.E1F555A9@zahav.net.il> <347_MlxDFbWe$GA.149@forums.sybase.com>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:28351
Article PK: 160381

Let me clarify myself:
I intentionally caused the segmentation fault in my Corba object in order to
check how EAS would behave.
As I assumed, the EAS process aborted when one of its threads (the one with my
Corba object) caused the memory fault.
This doesn't seem like a bug in EAS but rather a normal process behavior.
Such a behavior makes the whole Application Server's solution for running C++
objects useless.
My question is: Is there any solution for this? (Such as I suggested before:
run the Corba object in a separate process, perhaps, or any other solution).

Eyal Mishor

"Dave Wolf [Sybase]" wrote:

> Please contact technical support. Ive received another report of this, and
> we would consider this a bug after review.
>
> Dave Wolf
> Internet Applications Division
>
> Eyal Mishor <eyal_mi@zahav.net.il> wrote in message
> news:38AC2428.E1F555A9@zahav.net.il...
> > Hi all,
> > I hope someone can help me:
> > I tried to run Corba wrapped C++ objects in EAS, and the C++ object
> > caused a segmentation fault. Because this was in one of the EAS
> > threads, it caused it to abort!
> > Is it possible to configure EAS to run such objects in a seperate
> > process so that it won't be so easily disturbed by such an error?
> > Or is there another solution?
> >
> > Thanks in Advance,
> > Eyal Mishor
> >


Dave Wolf [Sybase] Posted on 2000-02-22 02:00:57.0Z
Newsgroups: sybase.public.easerver
From: "Dave Wolf [Sybase]" <dwolf@sybase.com>
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Date: Mon, 21 Feb 2000 21:00:57 -0500
Lines: 52
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 5.00.2314.1300
X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2314.1300
NNTP-Posting-Host: 158.159.8.19
Message-ID: <347_xgtVskNf$GA.183@forums.sybase.com>
References: <347_38AC2428.E1F555A9@zahav.net.il> <347_MlxDFbWe$GA.149@forums.sybase.com> <347_38ADB255.97560768@zahav.net.il>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:28252
Article PK: 154644

Im not sure I agree this is normal. I would think we could have EAS handle
this more gracefully. I would open a case.

Dave Wolf
Internet Applications Division

Eyal Mishor <eyal_mi@zahav.net.il> wrote in message
news:38ADB255.97560768@zahav.net.il...
> Let me clarify myself:
> I intentionally caused the segmentation fault in my Corba object in order
to
> check how EAS would behave.
> As I assumed, the EAS process aborted when one of its threads (the one
with my
> Corba object) caused the memory fault.
> This doesn't seem like a bug in EAS but rather a normal process behavior.
> Such a behavior makes the whole Application Server's solution for running
C++
> objects useless.
> My question is: Is there any solution for this? (Such as I suggested
before:
> run the Corba object in a separate process, perhaps, or any other
solution).
>
> Eyal Mishor
>
> "Dave Wolf [Sybase]" wrote:
>
> > Please contact technical support. Ive received another report of this,
and
> > we would consider this a bug after review.
> >
> > Dave Wolf
> > Internet Applications Division
> >
> > Eyal Mishor <eyal_mi@zahav.net.il> wrote in message
> > news:38AC2428.E1F555A9@zahav.net.il...
> > > Hi all,
> > > I hope someone can help me:
> > > I tried to run Corba wrapped C++ objects in EAS, and the C++ object
> > > caused a segmentation fault. Because this was in one of the EAS
> > > threads, it caused it to abort!
> > > Is it possible to configure EAS to run such objects in a seperate
> > > process so that it won't be so easily disturbed by such an error?
> > > Or is there another solution?
> > >
> > > Thanks in Advance,
> > > Eyal Mishor
> > >
>


Evan Ireland Posted on 2000-02-23 01:26:52.0Z
Newsgroups: sybase.public.easerver
Date: Wed, 23 Feb 2000 14:26:52 +1300
From: Evan Ireland <eireland@sybase.com>
Organization: Sybase, Inc.
X-Mailer: Mozilla 4.7 [en] (WinNT; U)
X-Accept-Language: en
MIME-Version: 1.0
To: "Dave Wolf [Sybase]" <dwolf@sybase.com>
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Content-Type: multipart/mixed; boundary="------------EAE6B923C05576D0E2FDA84F"
Lines: 1542
NNTP-Posting-Host: 130.214.8.39
Message-ID: <347_38B3375C.FB77D993@sybase.com>
References: <347_38AC2428.E1F555A9@zahav.net.il> <347_MlxDFbWe$GA.149@forums.sybase.com> <347_38ADB255.97560768@zahav.net.il> <347_xgtVskNf$GA.183@forums.sybase.com>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:28117
Article PK: 160004

Design Patterns for Legacy Application Integration with EA Server Evan Ireland, Sybase EA Server Engineering, 17 August 1999 Contents

  • Introduction
  • Application Integrators
  • Data Access Solutions
  • Pattern: C++ wrapper for internal process
    • Description
    • Prerequisites
    • Advantages
    • Disadvantages
    • Variations
  • Pattern: Java wrapper for external process
    • Description
    • Prerequisites
    • Example: ProcessWrapper class
    • Example: RunCommandImpl class
    • Example: CalculatorImpl class
    • Advantages
    • Disadvantages
    • Variations
  • Pattern: Message queue for external process
    • Description
    • Prerequisites
    • Example: TextMessageBroker IDL
    • Example: TextMessageBroker class
    • Example: KeyGeneratorImpl class
    • Example: CalculatorHtml servlet
    • Example: CalculatorMain process
    • Advantages
    • Disadvantages
Introduction

The purpose of this document is to present a number of design patterns that may be of use to developers who need to integrate existing (legacy) applications with EA Server.

If some of the desired integration can be achieved using EA Server Application Integrators or Sybase Data Access Solutions, it would be advisable to consider using them as a part of an integration solution.

Application Integrators

EAServer 3.0 includes Application Integrators for CICS and Stored Procedures that enable developers to integrate Web and component-based applications with back-end enterprise systems. Sybase has also aligned with Planetworks in a co-development effort to "EAServer enable" Planetworks' Interspace to provide extensions to CICS (ECI and EPI), Tuxedo, and MQ Series environments.

Note: the Application Integrators are bundled with EA Server, but are separately licensed.

Data Access Solutions

Sybase data access solutions allow your users to access virtually any enterprise data source from today's desktop applications and application servers. Sybase offers four different categories of data-access products, allowing you to build a solution scaled to the particular needs of your enterprise:

  • DirectConnect allows access to MVS, AS/400 and LAN-based data sources
  • OmniConnect allows access to multiple disparate data sources as though they were a single database
  • InfoHub allows transparent dynamic SQL access to nonrelational mainframe data sources, including VSAM, Adabas, IDMS, IMS and CA-DATACOM
  • jConnect™ is a full Java implementation of the Java Database Connectivity (JDBC) standards. It provides Java developers native database access in a multi-tier environment. jConnect for JDBC provides high-performance, direct access to the complete family of Sybase products including Adaptive Server Enterprise, Adaptive Server Anywhere, Sybase IQ and Replication Server.
Pattern: C++ wrapper for internal process Description:

A C++ wrapper component is created to access the legacy application code through C/C++ function calls. The legacy code is linked with the dynamic library (.dll/.so) for the C++ wrapper component, and thereby runs within the same process address space as the component (within the EA Server process). If the legacy code needs to retain a client context (conversational state) or legacy system resources between calls from a particular client, this state can be stored in instance variables for the wrapper component's C++ class. The C++ wrapper component presents a CORBA IDL interface to its clients.

Prerequisites:
  • The legacy code should be accessible through C/C++ function calls (but see Variations below).
  • The legacy code should be thread-safe, unless it is acceptable to have EA Server automatically serializing access to the legacy code by disabling the wrapper component's Concurrency option.
  • The legacy code should not use thread-local storage, unless it is acceptable to have EA Server retaining an instance-thread association by enabling the wrapper component's Bind Thread option.
  • The execution environment for the legacy code must be compatible with EA Server's threading model, i.e. native operating system threads on the host platform.
Advantages:
  • If the legacy code is thread-safe, this approach should give very good response times and system throughput.
  • If the wrapper component is thread-safe and stateless, its Sharing option can be enabled, thus conserving memory by avoiding the creation of multiple wrapper component instances.
  • The wrapper component's Pooling option can be enabled, allowing legacy system resources that are expensive to acquire or release to be retained along with a pooled instance of the wrapper component, ready to be used in servicing a future client request. Note: Pooling is preferable to Sharing when legacy system resources are involved.
Disadvantages:
  • Legacy code which is crash-prone may bring down the EA Server process.
  • Enabling access to legacy code through C/C++ function calls may be time consuming, if the legacy code is coded in another language using language constructs that do not map simply to legal C/C++ function argument types. It might require a lot of additional coding in the legacy environment, or it might require C/C++ or legacy environment skills that are not readily available to the integration team.
  • Disabling the Concurrency option to support non-thread-safe legacy code may severely limit the scalability of the integration solution. In other words, the client response times may be too high, or the system throughput may be too low.
  • Enabling the Bind Thread option to support legacy code that uses thread-local storage may limit the scalability of the integration solution if concurrent access by hundreds of clients is required, since a single EA Server process is limited on some platforms in the number of threads it can support due to the virtual memory that is assigned to each thread's stack by the server operating system. One possible workaround to this problem, if the wrapper component is stateless, is to use an EA Server cluster since each server in a cluster runs with its own virtual address space, i.e. run multiple EA Server instances on a single host.
Variations:
  • Although C++ usually offers the best chance of being able to perform in-process integration, this pattern can be used equally well with any EA Server component type that allows in-process communication with the legacy code, e.g. COM, Java, PowerBuilder.
Pattern: Java wrapper for external process Description:

A Java wrapper component is created to access the legacy application code through inter-process communication with the standard input and output of an external process containing the legacy code. The external process is initiated by the wrapper component, using either a separate process per request or a pool of reusable processes. When a client calls a method on the wrapper component, the wrapper component method converts the input parameters into a 'request' message, writes the 'request' message to the input stream of the external process, then reads a 'response' message from the output stream of the external process, and finally converts the 'response' message into return/output parameters for the client-invoked method. The Java wrapper component presents a CORBA IDL interface to its clients.

Prerequisites:
  • The legacy application environment must provide access to the standard input or output stream, and should provide access to command-line arguments.
  • The legacy application environment must allow for the creation of a program that can be invoked as an external process using the java.lang.Runtime.exec method.
Example: ProcessWrapper class package Test; /** ** A base/utility class for external process wrapper components. A wrapper ** component can either inherit from or delegate to this class. This class ** also implements the CtsServices::GenericService interface so that it can ** be used as an EA Server service component (see 'stop' method for details). **/ class ProcessWrapper { /** ** A shared table of process caches, available to all instances of the ** ProcessWrapper class. This enables a single ProcessWrapper class to ** be effectively reused by any number of process wrapper components. **/ private static java.util.Hashtable _table = new java.util.Hashtable(); class Cache { String name; java.util.Vector procs; // a vector of running processes int count; // how many processes in total (cached or not) int min; // minimum number of processes (requires service component) int max; // maximum number of processes } private Cache _cache; // cache of external processes. private String _command; // command used to initiate external process. private String _endInput; // what must be appended to each request? private String _endOutput; // what determines the end of a response? private String _isExiting; // what string notifies graceful process exit. private boolean _waitFor; // are we using a process-per-request policy? private boolean _zeroValue; // do we check process exit status? private char[] _chars; // buffer used when receiving responses. private static boolean _running; // set in running service private static boolean _stop; // set to stop running service. /** ** Initialize the wrapper. This can be called once in the wrapper component's ** constructor, or once per request, depending on whether the parameters vary ** between requests. Note: when delegating to (rather than inheriting from) ** the ProcessWrapper class, you must use the other 'init' method. **/ public void init (String command, int min, int max, String endInput, String endOutput, String isExiting, boolean waitFor, boolean zeroValue) { init(getClass().getName(), command, min, max, endInput, endOutput, isExiting, waitFor, zeroValue); } /** ** Initialize the wrapper. This can be called once in the wrapper component's ** constructor, or once per request, depending on whether the parameters vary ** between requests. The cache name would normally be the wrapper component's ** class name, but could be an arbitrary name (or the wrapper component's ** class name with an arbitrary suffix) in order to allow a single wrapper ** component to access multiple caches. **/ public void init (String cache, String command, int min, int max, String endInput, String endOutput, String isExiting, boolean waitFor, boolean zeroValue) { _command = command; _endInput = endInput; _endOutput = endOutput; _isExiting = isExiting; _waitFor = waitFor; // true = enable process-per-request policy _zeroValue = zeroValue; // true = check for zero exit value _chars = new char[64]; // may be expanded by the 'process' method if (_table == null) { throw new org.omg.CORBA.OBJ_ADAPTER("shutdown"); } synchronized (_table) { _cache = (Cache)_table.get(cache); if (_cache == null) { _cache = new Cache(); _cache.name = cache; _cache.procs = new java.util.Vector(); _cache.count = 0; _cache.min = min; _cache.max = max; // Note: the parameters are set only by the first call to 'init' // for this cache. _table.put(cache, _cache); } } } /** ** Obtain a process from the cache, or initiate a new process. **/ public Process getProcess() { return getProcess(false); } /** ** Obtain a process from the cache, or initiate a new process. Whether ** or not we are using a process-per-request policy, the cache max ** determines the maximum number of external processes that may be ** simultaneously active. If the max has been reached, we wait until ** a process is released or destroyed. **/ public Process getProcess(boolean forceNew) { if (_cache == null) { throw new org.omg.CORBA.INITIALIZE(getClass().getName()); } try { for (;;) { synchronized (_cache) { int n = _cache.procs.size(); if (! forceNew && n > 0) { Process process = (Process)_cache.procs.elementAt(n - 1); _cache.procs.removeElementAt(n - 1); return process; } if (forceNew || _cache.count < _cache.max) { Process process = Runtime.getRuntime().exec(_command); _cache.count++; return process; } _cache.wait(); } } } catch (Exception ex) { ex.printStackTrace(); System.out.println("ERROR: ProcessWrapper.getProcess: " + ex.toString() + ": wrapper '" + _cache.name + "'"); throw new org.omg.CORBA.NO_RESPONSE(ex.toString()); } } /** ** Destroy a running process. This is used for the process-per-request ** policy, or otherwise where there was an unexpected failure while ** communicating with the process, and we assume that the process will ** no longer function correctly. **/ public void destroy(Process process) { process.destroy(); synchronized (_cache) { _cache.count--; _cache.notify(); // other clients blocking in 'getProcess' } } /** ** Release a running process to the cache. Must not be used with the ** process-per-request policy. **/ public void release(Process process) { synchronized (_cache) { _cache.procs.addElement(process); _cache.notify(); // other clients blocking in 'getProcess' } } /** ** Obtain a process from the cache, and use it to process a request. ** The 'request' may be null if we are using the process-per-request ** policy and the external process has no standard input stream. For ** the process-per-request policy, the external process must be able ** to exit without detecting the 'end' of it's standard input stream. **/ public String process(String request) { Process process = getProcess(); java.io.InputStream input = process.getInputStream(); java.io.OutputStream output = process.getOutputStream(); java.io.Reader reader = new java.io.InputStreamReader(input); java.io.Writer writer = new java.io.OutputStreamWriter(output); boolean canReuse = true; try { // Send request to process. if (request != null) { writer.write(request + _endInput); writer.flush(); } // Get response from process. StringBuffer buffer = new StringBuffer(_chars.length); String response = ""; for (;;) { int nchars = reader.read(_chars); if (nchars < 1) { if (! _waitFor) { throw new Exception("EOF"); } break; } buffer.append(_chars, 0, nchars); response = buffer.toString(); if (_endOutput.length() > 0) { if (response.endsWith(_endOutput)) { response = response.substring(0, response.length() - _endOutput.length()); if (_endOutput.endsWith("\n") && response.endsWith("\r")) { // Remove trailing carriage return response = response.substring(0, response.length() - 1); } break; } } } if (_isExiting.length() > 0) { if (response.endsWith(_isExiting)) { // The process has returned a valid response, but has also // indicated it wishes to no longer be reused. response = response.substring(0, response.length() - _isExiting.length()); canReuse = false; } } // Check if we could use a larger buffer to improve efficiency // on the next call. if (response.length() > _chars.length) { _chars = new char[response.length()]; } // Wait for process completion if using process-per-request policy if (_waitFor) { process.waitFor(); if (_zeroValue) { int status = process.exitValue(); if (status != 0) { throw new Exception("exit status " + status); } } destroy(process); // this decrements _count } else if (! canReuse) { destroy(process); // this decrements _count } else { release(process); } // Wow, we made it! return response; } catch (Exception ex) { ex.printStackTrace(); System.out.println("ERROR: ProcessWrapper.process: " + ex.toString() + ": wrapper '" + _cache.name + "', command '" + _command + "', request: '" + request + "'"); destroy(process); throw new org.omg.CORBA.NO_RESPONSE(ex.toString()); } } /** ** Attempt to process a request several times, to account for possible ** failure of an external process. **/ public String process(String request, int retries) { for (int retry = 0;; retry++) { try { return process(request); } catch (org.omg.CORBA.NO_RESPONSE nr) { if (retry >= retries) { throw nr; } System.out.println("RETRY: ProcessWrapper.process: " + "wrapper '" + _cache.name + "', command '" + _command + "', request: '" + request + "'"); } } } /** ** This method is required for ProcessWrapper class to be used as an ** EA Server service component. **/ public void start() { } /** ** This method is required for ProcessWrapper class to be used as an ** EA Server service component. **/ public void run() { _running = true; _stop = false; try { while (_cache.min > 0) { int need; synchronized (_cache) { need = _cache.min - _cache.procs.size(); } for (int i = 0; i < need; i++) { release(getProcess(true)); // force new process } synchronized (_table) { _table.wait(60000); // re-fill process cache every minute } } } catch (Exception ex) { ex.printStackTrace(); } finally { _running = false; } } /** ** This method should be invoked during server restart/shutdown to ** kill any external processes that are still running, otherwise we ** might be unable to restart the server if the external processes ** are referencing the file descriptors for the server's network ** listeners. We also want to avoid ending up with 'orphan' ** external processes that must be manually terminated. **/ public void stop() { try { while (_running) { _stop = true; // Notify 'run' method to exit synchronized (_table) { _table.notifyAll(); } Thread.sleep(1000); // Wait for 'run' to exit } synchronized (_table) { for (java.util.Enumeration e = _table.elements(); e.hasMoreElements();) { Cache cache = (Cache)e.nextElement(); synchronized (cache) { int n = cache.procs.size(); for (int i = 0; i < n; i++) { Process process = (Process)cache.procs.elementAt(i); process.destroy(); } } } _table.clear(); } } catch (Exception ex) { ex.printStackTrace(); } } } Example: RunCommandImpl class package Test; /** ** A sample external process wrapper component that uses delegation, ** and initiates a separate external process for each request. ** Warning: since this component has methods that can execute arbitrary ** operating system commands, this component should not be deployed without ** roles that limit access to trusted users (system administrators). **/ public class RunCommandImpl { private ProcessWrapper _pw; public RunCommandImpl() { _pw = new ProcessWrapper(); } /** ** Run a command that takes all its input from command-line parameters. ** For example on a Unix system, the command "cal 2000" will return a ** calendar for the year 2000. **/ public String run(String command) { _pw.init(getClass().getName(), command, 0, 20, "", "", "", true, true); return _pw.process(null); } /** ** Run a command that takes some or all of its input from the standard ** input stream, but doesn't need to detect the end of its input stream ** before exiting. For example on a Unix system, the command "dc" with ** input "1 2 + p \n quit \n" will return "3". **/ public String runWithInput(String command, String input) { _pw.init(getClass().getName(), command, 0, 20, "", "", "", true, true); return _pw.process(input); } } Example: CalculatorImpl class package Test; /** ** A sample external process wrapper component that uses inheritance, ** and retains a pool of 'reusable' external processes. ** Note: "bc" is the standard Unix basic calculator program. **/ public class CalculatorImpl extends ProcessWrapper { public CalculatorImpl() { init("bc", 5, 20, "\n", "\n", "", false, false); } public String eval(String expr) { return process(expr); } } Advantages:
  • The legacy application may in fact support integration without any changes, e.g. the Unix bc basic calculator utility.
  • Minimal legacy coding skills will be required to build or modify an application in the legacy environment that can read requests from the standard input, stream, process them, and write responses to the standard output stream.
  • With a suitable framework, minimal Java programming skills will be required to achieve integration.
  • The wrapper component can be coded to recover transparently (or at least gracefully) if the external process crashes, e.g. public String eval(String expr) { return process(expr, 3); // try three times }
  • The external processes are initiated by the wrapper component, so no shell/command scripts need to be written to start them.
  • Reusable external processes can be started upon server startup, if that is desired (see the 'run' method in class ProcessWrapper).
  • External processes that have memory leaks may be reused until they voluntarily request shutdown (see the 'isExiting' parameter in the 'init' method in the ProcessWrapper class).
Disadvantages:
  • If a pool of reusable external processes is used, care must be taken during during server restart, shutdown or startup to kill any external processes that are still running. Otherwise it might not be possible to restart the server, or it might restart with all listeners on 'localhost' if the external processes are referencing the file descriptors for the server's network listeners. Also, the resulting 'orphaned' external processes will take up valuable system resources.
Variations:
  • Communication with the external processes may be done via files or sockets rather than standard input and output. When using files, it is advisable to have the wrapper component generate unique file names for communicating with the external processes, so that several external processes can be active simultaneously. The unique file names could be provided as command-line arguments to the operating system commands used to initiate external processes.
  • This pattern can be implemented in C/C++ on systems supporting the 'popen' C API, which can be used in place of java.lang.Runtime.exec.
Pattern: Message queue for external process Description:

A message broker component is used to communicate requests and replies through asynchrounous messages between the client and an external process, which may or may not reside on the same host as the EA Server. A client request is converted into a 'request' message. The 'request' message is sent to the message queue for the external process. The external process receives the 'request' message from its queue, processes the request and sends a 'reply' message to the original client's message queue. The client receives the 'reply' from its queue. The message broker component presents a CORBA IDL interface to clients.

Prerequisites:
  • The legacy application platform must support Java, or be a supported EA Server client platform, or have access to a third party IIOP 1.0 compliant client ORB.
Example: TextMessageBroker IDL #include <BCD.idl> module Test { struct MessageKey { BCD::Binary value; }; struct MessageQueue { BCD::Binary value; }; struct TextMessage { MessageKey key; string props; string replyTo; string text; }; interface TextMessageBroker { string getUniqueName ( ); MessageQueue getMessageQueue ( in string consumer ); MessageKey getMessageKey ( ); MessageKey next ( in MessageQueue queue, in long wait ); void acknowledge ( in MessageKey key ); void send ( in string queue, in TextMessage theMessage ); TextMessage receive ( in MessageKey key, in long lock ); }; }; Example: TextMessageBroker class package Test; import org.omg.CORBA.*; import java.util.*; import java.lang.Object; public class TextMessageBrokerImpl { /** ** Compare 'n' bytes from 'x' (from offset 'xo') with 'y' ** (from offset 'yo'). **/ private static boolean sameBytes(int n, byte[] x, int xo, byte[] y, int yo) { if (xo + n > x.length || yo + n > y.length) { return false; } for (int i = 0; i < n; i++) { if (x[xo + i] != y[yo + i]) { return false; } } return true; } /** ** This wraps a message when stored in a message queue. **/ class QueuedMessage { /** ** The message! **/ TextMessage message; /** ** The message key from 'message' with owner's session information. ** first 16 bytes as unique key for this message ** second 16 bytes as unique key for this session ** remaining bytes as consumer name, in UTF-8 form ** If this message currently has no owner, then this member is null. **/ byte[] session; /** ** The time that this message's lock will expire, or 0 if not locked. **/ long unlock; } /** ** A transient (in-memory) queue of messages for a consumer. **/ class Consumer { private Vector _vector; private QueuedMessage _repeat; Consumer() { _vector = new Vector(); _repeat = null; } boolean isEmpty() { return _vector.size() == 0; } QueuedMessage next() { long now = new java.util.Date().getTime(); int n = _vector.size(); for (int i = 0; i < n; i++) { QueuedMessage qm = (QueuedMessage)_vector.elementAt(i); if (qm.session == null || now >= qm.unlock) { return qm; } } return null; } QueuedMessage get(byte[] key, int lock) { if (lock == 0 && _repeat != null && sameBytes(16, key, 0, _repeat.message.key.value, 0)) { // The client may have had a communications failure and is // requesting the same message as on the last 'get' call // for this queue, and since the 'lock' is zero, we removed // the message from the _vector on the last 'get' call. return _repeat; } long now = new java.util.Date().getTime(); int n = _vector.size(); for (int i = 0; i < n; i++) { QueuedMessage qm = (QueuedMessage)_vector.elementAt(i); if (sameBytes(16, key, 0, qm.message.key.value, 0)) { // This queued message is the one we're looking for if (qm.session == null || now >= qm.unlock || sameBytes(16, key, 16, qm.session, 16)) { // Either this message is not locked, the lock has // expired, or this client is already the lock owner. if (lock == 0) { // Client requested auto-acknowledgement qm.unlock = 0; _vector.removeElementAt(i); _repeat = qm; } else { // Lock the message so that it won't be returned by // another call to 'get' in the next 'lock' seconds. qm.session = key; qm.unlock = new java.util.Date().getTime() + (lock * 1000); _repeat = null; } return qm; } } } return null; } void put(QueuedMessage qm) { _vector.insertElementAt(qm, _vector.size()); } QueuedMessage remove(byte[] key) { long now = new java.util.Date().getTime(); int n = _vector.size(); for (int i = 0; i < n; i++) { QueuedMessage qm = (QueuedMessage)_vector.elementAt(i); if (qm.session != null && sameBytes(key.length, key, 0, qm.session, 0)) { _vector.removeElementAt(i); return qm; } } return null; } } private static Hashtable _consumers = new Hashtable(); private Consumer getConsumer (String consumer) { synchronized (_consumers) { Consumer c = (Consumer)_consumers.get(consumer); if (c == null) { c = new Consumer(); _consumers.put(consumer, c); } return c; } } /** ** Get the consumer name encoded within a MessageKey. **/ private String getConsumerId (MessageKey key) { if (key.value.length < 32) { throw new BAD_PARAM("TextMessageBroker.getConsumerId: bad MessageKey value"); } byte[] consumerIdBytes = new byte[key.value.length - 32]; System.arraycopy(key.value, 32, consumerIdBytes, 0, key.value.length - 32); return com.sybase.CORBA.utf.BinaryToString.convert(consumerIdBytes); } /** ** Get the consumer name encoded within a MessageQueue. **/ private String getConsumerId (MessageQueue mq) { if (mq.value.length < 16) { throw new BAD_PARAM("TextMessageBroker.getConsumerId: bad MessageQueue value"); } byte[] consumerIdBytes = new byte[mq.value.length - 16]; System.arraycopy(mq.value, 16, consumerIdBytes, 0, mq.value.length - 16); return com.sybase.CORBA.utf.BinaryToString.convert(consumerIdBytes); } /** ** Return a unique name for a temporary consumer. **/ public String getUniqueName() { byte[] key = KeyGeneratorImpl.key16(); return "_$" + com.sybase.CORBA.hex.BinaryToString.convert(key, 0, key.length); } /** ** Return the message queue for a consumer. **/ public MessageQueue getMessageQueue (String consumer) { byte[] sessionKey = KeyGeneratorImpl.key16(); byte[] consumerId = com.sybase.CORBA.utf.StringToBinary.convert(consumer); byte[] value = new byte[sessionKey.length + consumerId.length]; System.arraycopy(sessionKey, 0, value, 0, 16); System.arraycopy(consumerId, 0, value, 16, consumerId.length); return new MessageQueue(value); } /** ** Return a unique message key for a new message. **/ public MessageKey getMessageKey() { return new MessageKey(KeyGeneratorImpl.key16()); } /** ** Send a message to the specified message queue. **/ public void send (String queue, TextMessage theMessage) { QueuedMessage qm = new QueuedMessage(); qm.message = theMessage; qm.session = null; qm.unlock = 0; Consumer c = getConsumer(queue); synchronized (c) { c.put(qm); c.notifyAll(); // clients waiting in 'next' } } /** ** Return the key for the next message in <code>queue</code>, or ** return an empty key if no message is available for ** <code>wait</code> seconds. **/ public MessageKey next (MessageQueue mq, int wait) { String consumer = getConsumerId(mq); Consumer c = getConsumer(consumer); for (;;) { try { QueuedMessage qm; synchronized (c) { qm = c.next(); if (qm == null && wait > 0) { c.wait(wait * 1000); qm = c.next(); } } if (qm == null) { // No message available - return empty message key return new MessageKey(new byte[0]); } else { byte[] key = new byte[16 + mq.value.length]; // Return a key with the unique 'session' bytes set System.arraycopy(qm.message.key.value, 0, key, 0, 16); System.arraycopy(mq.value, 0, key, 16, mq.value.length); return new MessageKey(key); } } catch (InterruptedException ignore) { } } } /** ** Receive the message with the specified <code>key</code>, or ** receive an empty message if <code>key</code> is empty as a ** result of a timed out call to <code>next</code>. ** <p>If <code>lock</code> is greater than zero, obtain a lock on ** the message which will time out after <code>lock</code> seconds. ** The lock should normally be released with <code>acknowledge</code> ** before it times out. ** <p>If <code>lock</code> is zero, the message is automatically ** acknowledged. **/ public TextMessage receive (MessageKey key, int lock) { if (key.value.length == 0) { // The key returned by a timed out call to 'next'. return new TextMessage(new MessageKey(new byte[0]), "", "", ""); } String consumer = getConsumerId(key); Consumer c = getConsumer(consumer); QueuedMessage qm; synchronized (c) { qm = c.get(key.value, lock); } if (qm == null) { // Message is no longer available in queue. return new TextMessage(new MessageKey(new byte[0]), "", "", ""); } else { return new TextMessage(key, qm.message.props, qm.message.replyTo, qm.message.text); } } /** ** Acknowledge the receipt of a message. If the lock that was ** acquired by <code>receive</code> has timed out, then return FALSE. ** Otherwise remove the message from the queue it was received from, ** and return TRUE. ** Note: when <code>acknowledge</code> returns FALSE, is it advisable ** to roll back the active transaction, because when the lock times ** out for a received message, another client processing the same ** queue may receive the same message. This avoids processing the ** same message twice. **/ public boolean acknowledge (MessageKey key) { String consumer = getConsumerId(key); Consumer c = getConsumer(consumer); boolean remove = false; QueuedMessage qm; synchronized (c) { qm = c.remove(key.value); if (c.isEmpty() && consumer.startsWith("_$")) { // garbage collection for empty temporary queues remove = true; } } if (remove) { synchronized (_consumers) { _consumers.remove(consumer); } } return qm != null; } } Example: KeyGeneratorImpl class package Test; import org.omg.CORBA.*; import java.util.*; import java.lang.Object; import com.sybase.CosNaming.JaguarCosNaming; // we want to use getManagerURL import com.sybase.jaguar.server.Jaguar; /** ** Unique ID generator. **/ public class KeyGeneratorImpl { static int _n = 0; static byte[] _serverID = { 0, 0, 0, 0, 0, 0, 0, 0 }; /** ** Seconds since 1 January, 1970. **/ static int _unixTime = 0; /** ** Unique ID within the interval of _unixTime (seconds). **/ static int _uniqueID = 0; static { setServerID(); } /** ** Generate a 16 byte unique ID for an object or request, as ** ** 4 bytes : primary listener host IP ** 2 bytes : primary listener port ** 2 bytes : server's restart cycle ** 4 bytes : current time (seconds since 1 January, 1970) ** 4 bytes : wrapping 32 bit number **/ public static byte[] key16() { int ut = (int)(new java.util.Date().getTime() / 1000); int id; synchronized (_serverID) { if (ut != _unixTime) { _unixTime = ut; _uniqueID = 0; } id = ++_uniqueID; } byte[] key = new byte[16]; System.arraycopy(_serverID, 0, key, 0, 8); bigEndian(ut, key, 8); bigEndian(id, key, 12); return key; } /** ** Set _serverID to server's IP address (4 bytes, big endian), ** followed by port (2 bytes, big endian), followed by the server's ** cycle (2 bytes, big endian). The IP address we use is the one for ** the server's primary IIOP listener. When running in Jaguar 3.0 which ** doesn't have .cycle files, the cycle will always be zero. **/ private static void setServerID() { try { String url = JaguarCosNaming.getManagerURL(); // url has format "iiop://localhost:9000:U$...:P$..." // we want to extract the host & port if (url.startsWith("iiop://")) { url = url.substring(7); } int pos = url.indexOf(":U$"); if (pos != -1) { url = url.substring(0, pos); } pos = url.indexOf(':'); String host = ""; String ps = ""; if (pos != -1) { host = url.substring(0, pos); ps = url.substring(pos + 1); } short port = (short)Integer.parseInt(ps); short cycle = 0; java.net.InetAddress addr = java.net.InetAddress.getByName(host); System.arraycopy(addr.getAddress(), 0, _serverID, 0, 4); bigEndian(port, _serverID, 4); bigEndian(cycle, _serverID, 6); } catch (Throwable ex) { ex.printStackTrace(); System.out.println("Warning: KeyGenerator initialization failed"); } } private static void bigEndian(short value, byte[] buffer, int offset) { buffer[offset] = (byte)((int)(value >>> 8) & 255); buffer[offset + 1] = (byte)((int)value & 255); } private static void bigEndian(int value, byte[] buffer, int offset) { buffer[offset] = (byte)((value >>> 24) & 255); buffer[offset + 1] = (byte)((value >>> 16) & 255); buffer[offset + 2] = (byte)((value >>> 8) & 255); buffer[offset + 3] = (byte)(value & 255); } } Example: CalculatorHtml servlet package Test; import javax.servlet.*; import org.omg.CORBA.*; import java.lang.Object; /** ** A servlet that processes an HTTP request by communicating with ** an external process via a message queue. The external process ** may reside on another host. ** Note: this servlet is single-threaded. **/ public class CalculatorHtml implements Servlet { private ServletConfig _sc; private TextMessageBroker _mb; private String _me; private MessageQueue _mq; public void init(ServletConfig sc) { _sc = sc; String[] args = { "-org.omg.CORBA.ORBClass", "com.sybase.CORBA.ORB" }; ORB orb = ORB.init(args, null); _mb = TextMessageBrokerHelper.narrow(orb.string_to_object("Test/TextMessageBroker")); _me = _mb.getUniqueName(); _mq = _mb.getMessageQueue(_me); } public ServletConfig getServletConfig() { return _sc; } public void service(ServletRequest request, ServletResponse response) { try { // The client tries to access a URL such as: // http://host:port/servlet/Test.CalculatorHtml?expr=66 String expr = request.getParameter("expr"); TextMessage message = new TextMessage(_mb.getMessageKey(), "", _me, expr); _mb.send("Test/Calculator", message); TextMessage reply = _mb.receive(_mb.next(_mq, 600), 10); String result = reply.text; ServletOutputStream out = response.getOutputStream(); out.println(expr + " = " + result); } catch (Exception ex) { throw new RuntimeException(ex.toString()); } } public String getServletInfo() { return "Test/CalculatorHtml"; } public void destroy() { } } Example: CalculatorMain process package Test; import org.omg.CORBA.*; import java.lang.Object; /** ** A sample external process wrapper using a message queue. ** Note: "bc" is the standard Unix basic calculator program. **/ public class CalculatorMain { /** ** A thread that monitors a message queue for new requests, ** processes requests by delegating to an external process, ** and sends replies to the request sender. **/ class WorkerThread extends Thread { private TextMessageBroker _mb; private MessageQueue _mq; private CalculatorImpl _calc; WorkerThread(TextMessageBroker mb, MessageQueue mq, CalculatorImpl calc) { _mb = mb; _mq = mq; _calc = calc; } public void run() { for (;;) { try { TextMessage message = _mb.receive(_mb.next(_mq, 600), 60); if (message.key.value.length != 0) { String expr = message.text; String result = _calc.eval(expr); TextMessage reply = new TextMessage(_mb.getMessageKey(), "", "", result); _mb.send(message.replyTo, reply); _mb.acknowledge(message.key); } } catch (org.omg.CORBA.COMM_FAILURE cf) { cf.printStackTrace(); // Application server is down, wait 5 minutes for it to restart try { Thread.sleep(300000); } catch (InterruptedException ignore) { } } catch (Exception ex) { ex.printStackTrace(); } } } } public static void main(String[] args) throws Exception { new CalculatorMain().run(args); } /** ** Start a number of threads, each of which handles messages from ** a queue by delegating to an external process. **/ public void run(String[] args) throws Exception { if (args.length != 1) { usage(); } String[] orbArgs = { "-org.omg.CORBA.ORBClass", "com.sybase.CORBA.ORB" }; ORB orb = ORB.init(orbArgs, null); TextMessageBroker mb = TextMessageBrokerHelper.narrow(orb.string_to_object(args[0])); for (int i = 0; i < 20; i++) { MessageQueue mq = mb.getMessageQueue("Test/Calculator"); new WorkerThread(mb, mq, new CalculatorImpl()).start(); } System.in.read(); synchronized (orb) { orb.wait(); } } private static void usage() { System.out.println("Usage: java Test.CalculatorMain iiop://host:port"); } } Advantages:
  • The legacy application platform does not need to host an application server (it only needs to act as a client to EA Server). This means that it is easier to control:
    • Resource utilization on the legacy application platform.
    • Security on the legacy application platform.
  • As the application becomes more complex, and new features are added, the full functionality of EA Server is available to extend the functionality made available from the legacy environment.
  • Management of the external processes can be kept separate from EA Server, if this is desirable.
Disadvantages:
  • The use of a message broker component makes the solution architecture more complicated than it might otherwise be.


Eyal Mishor Posted on 2000-02-24 22:07:51.0Z
Newsgroups: sybase.public.easerver
Date: Fri, 25 Feb 2000 00:07:51 +0200
From: Eyal Mishor <eyal_mi@zahav.net.il>
X-Mailer: Mozilla 4.6 [en] (Win95; I)
X-Accept-Language: en
MIME-Version: 1.0
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Lines: 16
NNTP-Posting-Host: 213.8.7.21
Message-ID: <347_38B5ABB7.AC7EB71A@zahav.net.il>
References: <347_38AC2428.E1F555A9@zahav.net.il> <347_MlxDFbWe$GA.149@forums.sybase.com> <347_38ADB255.97560768@zahav.net.il> <347_xgtVskNf$GA.183@forums.sybase.com> <347_38B3375C.FB77D993@sybase.com>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:27870
Article PK: 159571

Thank you for the educational material !

My legacy code isn't thread safe so I'm forced to choose the option of
having the C++ objects outside the server.
How can I share a transaction between objects inside the server and my
outside C++ objects (my objects interacts with a database, so I want to
be able to rollback their actions in case of problems) ?
Can I use the server as a TP monitor to accomplish this ? if yes how ?

Another question related to the subject:
What C++ compilers (besides CC 4.2) can I use to compile C++ object that
sit inside the server ?

Eyal Mishor


Evan Ireland Posted on 2000-02-25 00:32:24.0Z
Newsgroups: sybase.public.easerver
Date: Fri, 25 Feb 2000 13:32:24 +1300
From: Evan Ireland <eireland@sybase.com>
Organization: Sybase, Inc.
X-Mailer: Mozilla 4.7 [en] (WinNT; U)
X-Accept-Language: en
MIME-Version: 1.0
To: Eyal Mishor <eyal_mi@zahav.net.il>
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Lines: 15
NNTP-Posting-Host: vpn-eme-022.sybase.com 130.214.8.22
Message-ID: <347_38B5CD98.9EF74F3B@sybase.com>
References: <347_38AC2428.E1F555A9@zahav.net.il> <347_MlxDFbWe$GA.149@forums.sybase.com> <347_38ADB255.97560768@zahav.net.il> <347_xgtVskNf$GA.183@forums.sybase.com> <347_38B3375C.FB77D993@sybase.com> <347_38B5ABB7.AC7EB71A@zahav.net.il>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:27852
Article PK: 159558


Eyal Mishor wrote:
>
> What C++ compilers (besides CC 4.2) can I use to compile C++ object that
> sit inside the server ?

If you find any that don't work, please let us know.

You need a C++ compiler that supports C++ exceptions, other than that we have
tried very hard to ensure that any C++ compiler will work.
________________________________________________________________________________

Evan Ireland Sybase EA Server Engineering eireland@sybase.com
Wellington - New Zealand +64 4 934-5856


Dave Wolf [Sybase] Posted on 2000-02-24 22:14:05.0Z
Newsgroups: sybase.public.easerver
From: "Dave Wolf [Sybase]" <dwolf@sybase.com>
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Date: Thu, 24 Feb 2000 17:14:05 -0500
Lines: 25
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 5.00.2919.6600
X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6600
NNTP-Posting-Host: 158.159.8.12
Message-ID: <347_zVBd9Txf$GA.274@forums.sybase.com>
References: <347_38AC2428.E1F555A9@zahav.net.il> <347_MlxDFbWe$GA.149@forums.sybase.com> <347_38ADB255.97560768@zahav.net.il> <347_xgtVskNf$GA.183@forums.sybase.com> <347_38B3375C.FB77D993@sybase.com> <347_38B5ABB7.AC7EB71A@zahav.net.il>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:27868
Article PK: 159570

If the code isnt thread safe, just disable concurrency and enable bind
thread.

Dave Wolf
Internet Applications Division

"Eyal Mishor" <eyal_mi@zahav.net.il> wrote in message
news:38B5ABB7.AC7EB71A@zahav.net.il...
> Thank you for the educational material !
>
> My legacy code isn't thread safe so I'm forced to choose the option of
> having the C++ objects outside the server.
> How can I share a transaction between objects inside the server and my
> outside C++ objects (my objects interacts with a database, so I want to
> be able to rollback their actions in case of problems) ?
> Can I use the server as a TP monitor to accomplish this ? if yes how ?
>
> Another question related to the subject:
> What C++ compilers (besides CC 4.2) can I use to compile C++ object that
> sit inside the server ?
>
> Eyal Mishor
>


Eyal Mishor Posted on 2000-02-24 22:21:19.0Z
Newsgroups: sybase.public.easerver
Date: Fri, 25 Feb 2000 00:21:19 +0200
From: Eyal Mishor <eyal_mi@zahav.net.il>
X-Mailer: Mozilla 4.6 [en] (Win95; I)
X-Accept-Language: en
MIME-Version: 1.0
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Lines: 29
NNTP-Posting-Host: 213.8.7.21
Message-ID: <347_38B5AEDF.A56FABD9@zahav.net.il>
References: <347_38AC2428.E1F555A9@zahav.net.il> <347_MlxDFbWe$GA.149@forums.sybase.com> <347_38ADB255.97560768@zahav.net.il> <347_xgtVskNf$GA.183@forums.sybase.com> <347_38B3375C.FB77D993@sybase.com> <347_38B5ABB7.AC7EB71A@zahav.net.il> <347_zVBd9Txf$GA.274@forums.sybase.com>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:27865
Article PK: 159572

I can't afford doing it because of efficiency reasons - it will slow down
dramatically my system because currently we are running multiple instances of
the legacy objects in different processes.

Eyal Mishor

"Dave Wolf [Sybase]" wrote:

> If the code isnt thread safe, just disable concurrency and enable bind
> thread.
>
> Dave Wolf
> Internet Applications Division
>
> "Eyal Mishor" <eyal_mi@zahav.net.il> wrote in message
> news:38B5ABB7.AC7EB71A@zahav.net.il...
> > Thank you for the educational material !
> >
> > My legacy code isn't thread safe so I'm forced to choose the option of
> > having the C++ objects outside the server.
> > How can I share a transaction between objects inside the server and my
> > outside C++ objects (my objects interacts with a database, so I want to
> > be able to rollback their actions in case of problems) ?
> > Can I use the server as a TP monitor to accomplish this ? if yes how ?
> >
> > Another question related to the subject:
> > What C++ compilers (besides CC 4.2) can I use to compile C++ object that
> > sit inside the server ?
> >
> > Eyal Mishor
> >


Dave Wolf [Sybase] Posted on 2000-02-26 15:16:34.0Z
Newsgroups: sybase.public.easerver
From: "Dave Wolf [Sybase]" <dwolf@sybase.com>
Subject: Re: Segmentation fault in C++ objects causes EAS to abort
Date: Sat, 26 Feb 2000 10:16:34 -0500
Lines: 45
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 5.00.2919.6600
X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6600
NNTP-Posting-Host: vpn-eme-013.sybase.com 130.214.8.13
Message-ID: <347_04vaC0Gg$GA.251@forums.sybase.com>
References: <347_38AC2428.E1F555A9@zahav.net.il> <347_MlxDFbWe$GA.149@forums.sybase.com> <347_38ADB255.97560768@zahav.net.il> <347_xgtVskNf$GA.183@forums.sybase.com> <347_38B3375C.FB77D993@sybase.com> <347_38B5ABB7.AC7EB71A@zahav.net.il> <347_zVBd9Txf$GA.274@forums.sybase.com> <347_38B5AEDF.A56FABD9@zahav.net.il>
Path: forums-1-dub!forums-1-dub!forums-master.sybase.com!forums.sybase.com
Xref: forums-1-dub sybase.public.easerver:27742
Article PK: 159100

We have a design pattern that might help you but the NNTP server wont let me
post it. Ill send via email.

Dave Wolf
Internet Applications Division

"Eyal Mishor" <eyal_mi@zahav.net.il> wrote in message
news:38B5AEDF.A56FABD9@zahav.net.il...
> I can't afford doing it because of efficiency reasons - it will slow down
> dramatically my system because currently we are running multiple instances
of
> the legacy objects in different processes.
>
> Eyal Mishor
>
> "Dave Wolf [Sybase]" wrote:
>
> > If the code isnt thread safe, just disable concurrency and enable bind
> > thread.
> >
> > Dave Wolf
> > Internet Applications Division
> >
> > "Eyal Mishor" <eyal_mi@zahav.net.il> wrote in message
> > news:38B5ABB7.AC7EB71A@zahav.net.il...
> > > Thank you for the educational material !
> > >
> > > My legacy code isn't thread safe so I'm forced to choose the option of
> > > having the C++ objects outside the server.
> > > How can I share a transaction between objects inside the server and my
> > > outside C++ objects (my objects interacts with a database, so I want
to
> > > be able to rollback their actions in case of problems) ?
> > > Can I use the server as a TP monitor to accomplish this ? if yes how ?
> > >
> > > Another question related to the subject:
> > > What C++ compilers (besides CC 4.2) can I use to compile C++ object
that
> > > sit inside the server ?
> > >
> > > Eyal Mishor
> > >
>