Click here to Skip to main content
Click here to Skip to main content

XMLFoundation

By , 21 Dec 2012
 

XMLFoundation/XMLFoundation2012.jpg

Introduction

Welcome to XMLFoundation 2012. This December 21 build extends and widens the library interfaces with emphasis on the future in software design, and even style. XMLFoundation maps the data in raw XML to lists, arrays, strings, ints, and even int64's in the application layer. All of these data types have been supported for over a decade already. New interfaces in the 2012 version support mapping char(1 byte), short(2 bytes), and char buf[n bytes] to fully complete the mapping to every native C++ data type. The foundational GString is now indexed by 64 bit addressing which pushes all xml document size limitations into almost infinity. This long addressing scheme has been added in such a way that 32 bit applications will still use 64 bit addressing granting them the bounds of infinity as well. Benchmark tests confirm that XMLFoundation is the fastest approach for moving XML into the application layer. The overhead of pushing an extra 4 bytes on the call stack during tokenization is measurable but insignificant in light of all the stack operations eliminated by using a custom non SAX interface to the XML parser (Read details in the 'Faster than Fast' section). On 64 bit systems there is no performance penalty to pay at all since the registers are 64 bits wide already.

The GString is such a sexy article of engineering that it gets used to hold all types of streamed data in an application, not just XML. By design, the GString replaced ostream which the tokenizer (aka -the lexical analyzer or the XML Parser) was initially built with. By overloading the << operator it was a very simple task to port this work to a better stream class. In the times of 2012 we now deal with file sizes and offsets that require 64bit indexing on the average or above average home computer. Granted it will be many years before the average home computer allocates contiguous regions of memory that large - but high end servers do it already and they have registers that are 64 bits wide. To keep GString positioned to serve mankind in ALL situations it now uses a 64 bit index. Target the future.

A 32 bit test parsed xml containing element and attribute tags mapped to various lists, string and integers. This was executed while counting cpu cycles using the assembly code in GPerformanceProfile.cpp for these results running in a native 32 bit operating system that is not under WOW or virtualization:

Tokenizing with a 64 bit index in the new XMLFoundation 32 bit build on a 32 bit OS: (176,121) CPU cycles

Tokenizing with a 32 bit index in the old XMLFoundation 32 bit build on a 32 bit OS: (170,144) CPU cycles

By merely widening the integer index at the lowest level of the XML parser it caused the machine code produced by the C++ compiler to PUSH and POP more data onto the stack, hence it now takes more CPU cycles to process the same amount of XML. If you understand what caused the difference, then you can understand why the XMLFoundation is preferable to SAX if you want the fastest solution. Truly this is the fastest solution on earth for processing XML in 32 bit, even though it is now optimized for 64 bit. The fastest solution will be the one selected to process the largest XML data sets in the world because the decision will be made by an engineer not a politician. Those data sets will need this very large indexing scheme. Smaller data sets no longer need to worry that some freak occurrence (an exception) might (however unlikely) surpass 32 bit indexing thresholds. English words fail to express what raw numbers so emphatically and eloquently assert is the fastest way to process XML. Aside from all this raw horsepower produced through efficient algorithmic design, the application source code that uses XML is organized and simple.

The 2012 version also supports a new interface to access unparsed CDATA from the object directly in the memory buffer passed into the lexical analyzer that algorithmically instantiates objects for you. Several new examples have been added in December advancing the example documentation to include Inheritance of Mapping explaining how to use base object mappings. Another Sample explains custom Parsed and Unparsed Object Data handlers. If a picture is worth a thousand words, an example is worth ten thousand. "Open Source" projects are frequently unsupported and undocumented, however you will find that the ongoing commentating of source code is continuously being maintained and developed to make the toolkit more useful and productive in the hands of people who are new to using it. The detailed documentation is all in the source code, right where you need it. For example a comment was just recently added into ListAbstraction.h just above the StringCollectionAbstraction class that explains how that base class is used to store ANY data type into ANY data structure. That comment links to a new class called CDoubleArrayAbstraction in AbstractionsMFC.h that stores the data type "double" into MFC's array implementation called CArray. While the implementation was the point of interest of one person, the comments added will be the point of interest to even more people that need some other data type in some other kind of data structure.

As many of you know this project had no updates for 2 years while I was in prison serving time for "Escape".

The details of my case should disturb you. I would have been killed if some authorities had their way but I lived to code another day so you can be certain that I am going to make the most of every keystroke now. I added a folder called "Disturbing" to the root folder of the source code distribution that contains some serious arrays of 1's and 0's in various formats.

Welcome to XMLFoundation 2012.

1. XML In the Foundation

13. Object Model Navigation

2. The Solid Foundation

14. GUI Objects

3. History and Future

15. CORBA Objects

4. The Need for Objects from XML

16. COM Objects

5. Best of Breed

17. Object Caching and Instance Management

6. Don't Be Square

18. Parsed and Unparsed Object Data

7. Learn To Think Outside The Box

19. FiveLoaves (aka ServerCore)

8. New World Order

20. Plugins and Language Drivers

9. Faster than Fast

21. FiveLoaves Tunneling and Messaging

10. Object Factorization

22. XMLFoundation for Java

11. Member Mapping

23. About the author(s) of XMLFoundation

12. Inheritance of Mapping

24. Conclusion

XML in the Foundation

As the name suggests it provides a foundation for XML support in an application, however this is much more than just another XML parser. It applies a unique approach to handling XML that allows your application code to focus on the application rather than traversing DOM or subscribing to SAX events. The most unique feature of the XMLFoundation is the object oriented encapsulation that provides XML support in the application layer. XMLFoundation allows you to easily integrate XML with your GUI, or with your server objects, and it natively supports COM, DCOM, and CORBA objects. XMLFoundation contains a small, fast, and portable XML tokenizer that has been refined and optimized in many large software projects. My involvement with XML pre-dates the finalization of the XML 1.0 recommendation by W3C. For years, the only XML Parser that could match XMLFoundation tokenization performance was "Xpat" by James Clark - but as you will see the unique ability to bypass DOM and SAX altogether makes XMLFoundation the fastest solution available for moving XML to and from application layer objects - and it requires far less lines of code to do it. The performance of the stack based XML parser is at the top of its class for non-validating parsers. Parsing and tokenization is only half the task, the other half is getting the results into the member variables, lists, and objects that they need to be in to be useful in the application layer - it is in that task that XMLFoundation is in a class of its own. The performance is unparalleled because the memory buffer that contains the source XML parses directly into your custom class objects without ever being copied or temporarily stored in a DOM tree. It parses directly into your lists, objects, arrays, indexed data structures, and all native C++ data types. It even has support for common containers of element data such as MFC CStrings. It's been used in Java too. That said, speed of execution is less impressive than the speed of development and overall reduction in lines of code required to effectively use XML in your application. XML is in the Foundation, but the foundation does much more than just XML. It is also a web services framework implemented in ServerCore.cpp. It can be extended several ways for HTTP as well as for other protocols. This allows you to to build your application on a multi-threaded server blueprint that has been used on many platforms and it has been used to build servers that are not even XML based, but needless to say it works great for building an XML based server. The services framework supports a unique design approach for both static and dynamic server extensions and examples of both - but XMLFoundation does even more than XML and Web Services.

The Solid Foundation

If you are building an application that does not use XML and never will..... XMLFoundation is still a very valuable tool available to solve many very common development tasks. The data structure classes alone ( List, Hash, Stack, Tree, Array, QSort ) are very useful. They all have "Iterator" objects so that data structures can be read-referenced by multiple threads at the same time without blocking. The interface is standard to all data structures. If you find MFC or Rogue Wave Standard C++ library data structures useful, you will likely find XMLFoundation data structures even more so.

XMLFoundation also has standard algorithm implementations ( Encryption, Compression, Data hash, Encoding ). These are based on the works of other authors. They have been included into the XMLFoundation in a simplified build format. They all compile under C++, so if you are using them on AS/400, AIX, Solaris, Linux, or other like platforms - you do not even need to reference a C compiler from the makefile, only your C++ compiler. They are also organized into single .CPP files for each implementation - often a consolidation of many individual C source files in the original authors publications.

XMLFoundation also has a plethora of application utilities including ( Sorts, Performance Timers, Disk Directory, Exceptions, INI Profiles, Caching, String, Stream ). XMLFoundation has many utilities that MFC does not. They are complete, comment documented with examples, and thoroughly tested on many software projects.

XMLFoundation is very portable. It builds on all versions of Windows (Win95 through Windows8 and Windows Mobile). Portions were initially developed on a RISC machine, and it was used in Solaris and Linux as early as 2001. Some of the compilers that have been used to build XMLFoundation include: CC5.0, Xlc, IntelC++, KAIc++, ForteC++, Visual C++, Borland C++, and eMc++. However I believe it works with any C++ compiler found here, because it does not use namespaces, iostreams, or STL - all areas that are prone to porting problems from my experience. It does have template classes but their inclusion is optional as part of the implementation rather than part of the foundation. XMLFoundation and all the sample applications have recently been built and verified on Ubuntu and Fedora. The source is distributed with VC6 makefiles so that the source can be imported into projects using every version of the Microsoft compilers from 1998 through Visual Studio 2010. Now the source includes a Visual Studio 2012 project file with 32 and 64 bit targets defined.

The build dependencies are meticulously correct. Smart linkers leave out everything you don't use, so don't expect to see code bloat as a punishment for using XMLFoundation. Other development libraries were not designed as well from a build perspective. Your application will not load any DLL's as a result of using the XMLFoundation. Xfer is another project I manage that is built on the XMLFoundation for the platform independence - the code is tight and the product(s) built on XMLFoundation reflect that.

I suppose an entire article could be written about each of the foundational classes, and I'm certain that they will be written. They are all well commented and coded with a highly experienced approach. The String class uses stack space when possible to avoid heap allocations. It's the best string implementation I've ever seen. The INI Profile class uses triggers that allows your application to pick up real-time configuration changes much like RegNotifyChangeKeyValue() in the Windows SDK. Exceptions can be configured to unwind the call stack to a memory buffer like Java's printStackTrace(). The Tree has an iterator. The Directory can delete recursively - on all platforms. The Stack is entirely inline, with standard and macro methods - It could not be any faster if it was coded directly in assembly. The StringList puts MFC's CStringList to shame, just look at the interfaces. The GHash puts Microsoft's CMapStringToPtr to shame. It is unspeakably faster. Look at the "MFCTypesFromXML" example and see for yourself.

History and Future

You cannot build a house on foundation of wet cement that has not cured yet. With cement, minimizing stress prior to curing minimizes cracking in your foundation. The same is true of software. The XMLFoundation is solid and completely cured. It would be too bold to say that the XMLFoundation has no bugs in, but it has none that I am aware of and the code has been heavily used. It is a complete foundation. Building an application on any foundation like Java 1.0 or .NET 1.0 or anything 1.0 means that if you don't get slowed down by the bugs, you will be slowed down when you find all the missing functionality. This code was first released to the public July 4, 2002 - the XMLFoundation was already very mature for it's age - it came from a good family - it's mother had already been used on the largest software project in the world. Since then I have built several complex applications on it and many others have as well. It was completely stress tested with SMP hardware during a recent Fortune 50 proof of concept implementation. XMLFoundation interfaces are well established constants, no longer a curing foundation that is still forming.

The mother of the XMLFoundation was "The XML Object Framework", born in 1998 & 1999(it was a long labor) for a client of mine. The XMLFoundation was born the following year. The XMLFoundation sported a completely new implementation of the xml parser based on the custom GString stream class that was also born in 2000. XML Journal Magazine reviewed a product built on the early XMLFoundation object factorization and called it "5 Star / World Class" in XMLJournal Magazine Volume 2 Issue 7 (note: they did not review XMLFoundation they reviewed TransactXML). XMLFoundation was heavily developed the following two years before it became public in 2002. This project is mature and stable.

XMLFoundation absolutely IS the future in certain technology subsets. It is a gift to the world of engineering, and it comes with all the source code. Universities that want to teach algorithms, applications, or OO Design will find the XMLFoundation to be a great source code to base a curriculum on. Independent authors who want to write about cutting edge technology will find XMLFoundation a worthy subject. The future was written in the past.

The Need for Objects from XML

XML is data. “Objects from data” is not a new concept. Programmers have been doing that for years, even before they were called objects. We still need to get data into objects today. The data can be XML or a result set, and the object might be a CDialog, a CORBA Object, a COM object, or your own invention. You still need to get the same thing done. Programmers have been doing this as long as there have been programmers.

If you apply enough force you can make the cube fit into the round hole. If you apply enough force you can do anything - even police California. The brute force approach is to parse the XML into a DOM tree, and traverse the tree to gather the data required by application/object variables. This approach causes volumes of “simple” source code to move data from XML into Structured Objects, a poor approach with respect to implementation time and long term maintenance.

Alternatively, the OO approach generalizes this process into reusable functionality that enables objects to serialize to and from XML directly. OO is pronounced ohhh-ohhh - and it is short for Object Oriented (incase you didn't know) - it's poetic tech lingo - a code of it's own.

Software developers of every language have a similar need. They must either:

  1. Write their own Object-XML tools,
  2. Find some production quality framework ready to use or,
  3. Use brute force and budget for maintenance programmers.

Best of Breed

We can mostly rule out option A because it takes a lot of time and the purpose of the project is to build product not tools. Option C is also unwise if you have any long term plans for your product or want to be able to quickly add new features. Option B leaves several paths and it wouldn't be right for me to toot my own horn and tell you that XMLFoundation is the best option available in the entire software industry to accomplish this fundamental task - so I encourage you to research this yourself and I expect that you will agree XMLFoundation is not just the best free solution, it's the best solution.

It's difficult to directly compare XMLFoundation to other solutions because the utilities in XMLFoundation, and many of the features in XMLFoundation are not found in other solutions. That said, here is a starting point for your own research:

Microsoft developed the "Xml.Serialization.XmlSerializer", for C# but it only supports shallow serialization(no nested or complex objects) and it lacks many other features found in the XMLFoundation. I would wager that even the limited support it does provide is slower than XMLFoundation but I have not put the two technologies to a speed comparison.

Liquid Technologies has a nice XML Serialization library( 'XML Data Binding' in Liquid XML Studio $246) that is mostly fast, but I am aware that when serializing small strings it's about 5 times slower than MSXML. Most likely this is due to heap allocations. XMLFoundation avoids most heap allocations for small strings. Once again I've never compared the two in a performance race.

A product called CMarkup is a C++ library that sells for $249 and has more features than what Microsoft put together (enough that it can actually be used for real world development). It does not support parsing directly into the kinds of data structures that XMLFoundation does (tree, hash, etc) so a performance comparison would need to include that. I have never put it to a side by side performance test with XMLFoundation but if anyone reading this did it, I would like to hear the results.

IBM Developer Works has posted 2 or more XML Serialization libraries but they are based on an external XML Parser - so by nature of their design they must be slower.

XMLFoundation is free. No strings attached. There is not even a 'professional' version that costs money - this is the professional version.

The list goes on, and on, and on, and on of likeminded solutions.

Don't Be Square

From a procedural perspective we put data in square sets just to make programming simple. Consider this example data that is a "Customer" with a list of "Orders" where each order has a list of "LineItems". That is not a square dataset - but for the sake of the application layer we have forced it to be square for the last 4 decades.

CUSTOMER CUST_ID ORDER_ID ORDER_DATE LINEITEM_ID LINEITEM_DESC PRICE
Brian 777 1 July 4, 1777 7 Firecrackers $111
Brian 777 1 July 4, 1777 14 Ariel Shells $222
Brian 777 1 July 4, 1777 21 Party Favors $444
Brian 777 2 July 4, 2009 28 Attorney Fees $222
Brian 777 2 July 4, 2009 35 State Fines $555

The repetition in red filled the hole in to make non-square data be square. The data in red is normally a pointer reference to the last sort break at the DBMS kernel level, but various toolsets often expand it long form so that 1 instance of a "Row" object does not rely on the data in another instance. It's a terrible situation that has plagued applications for as long as I can remember. The problem is that in reality there is no such thing as a "Row" object - it was more of a temporary/tool-object to get the data into real objects like Customers, Orders and LineItems. Countless data access products in the form of VBX, OCX, ActiveX and various frameworks and libraries serve up square data sets to applications that MANUALLY code the transfer of data into their application objects with volumes of code that looked something like this:

Customer::Load()
{
    Tool.GetData()
   
while( Tool.MoreRows() )
    {
         Row = Tool.GetNextRow();
         // Loop until we find a sort break on OrderID
         if  (Row.GetColumn("Order_ID") != LastOrderID)
         {
              LastOrderID = Row.GetColumn("Order_ID")
     
              // Make an Order object - set the values - then add it to the customer
              Order = new  OrderObject;
              Order.date = Tool.GetColumn("Order_Date")
              Order.id = Tool.GetColumn("Order_ID")
              AddOrderToCustomer(Order)
         }
         // Make a new line item object - set the values - then add it to the order
         LineItem = new  LineItemObject;
         LineItem.id = Tool.GetColumn("LineItem_ID")
         LineItem.desc = Tool.GetColumn("LineItem_Desc")
         LineItem.price = Tool.GetColumn("Price")
     
         Order.AddLineItem( LineItem )
    }
}

Notice all the use of Tool that represents some sort of data set tool, class or library. Building software to accomplish this task of copying data into objects without such a tool would dramatically increase the lines of code required to move the square dataset into your application objects. Knowing what tools to use can be the difference between the success or failure of an entire project. One bad tool, or one missing tool can make all the difference in the world to a software developer.

Learn to Think Outside the Box

This is the same example data from the square result set represented in XML:

<Customer id=777>
    <Name>Brian</Name>
    <Order id=1>
        <Date>July 4, 1777</Date>
        <LineItem id=7>
            <Desc>Firecrackers</Desc>
            <Price>111</Price>
        </LineItem>
        <LineItem id=14>
            <Desc>Ariel Shells</Desc>
            <Price>222</Price>
        </LineItem>
        <LineItem id=21>
            <Desc>Party Favors</Desc>
            <Price>444</Price>
        </LineItem>
    </Order>
    <Order id=2>
        <Date>July 4, 2009</Date>
        <LineItem id=72>
            <Desc>Attorney Fees</Desc>
            <Price>222</Price>
        </LineItem>
        <LineItem id=42>
            <Desc>State Fines</Desc>
            <Price>555</Price>
        </LineItem>
    </Order>
</Customers>

There is nothing square about XML. XML is an N-airy tree. That's why we naturally use DOM (Document Object Model) to traverse the data. For 1000's of years we thought that the world was flat. Engineers made it be square because that was easier for them to cope with and now we live in the days where it begins to take it's true shape. Unfortunately as of 2010, the opportunity of the paradigm data shape shift has not been harnessed by most programmers that grew up in the square world and are only familiar with square tools. They take the most obvious development path. If you presented the problem of sorting to someone who has no tools, they will likely build a "bubble sort" - because that is the most obvious and immediate solution.

Typically the XML is parsed into a tree structure. This means that the linear and contiguous memory buffer of source XML is copied into many fragmented pieces of memory across the heap - each element and in many cases each token gets it's own heap space. This makes the XML elements and attributes programmatically accessible with loops and recursion, just like Tool did for square datasets. The XML parser puts the Elements and Attributes into this temporary fragmented memory tree structure so that the application programmer can get at the information to copy it once more into a final structure that can be displayed on the GUI or used by the application. It is likely going to take as much or more code to get from the temporary DOM tree into the objects as it did to get from the square result set into the objects. In many cases it will require recursion that is difficult to debug - much more difficult than the old fashioned iterative code required to copy from square result sets. Below is a code sample of some common tasks:

//Due to the large amount of code to change a DOM node name this article only 
//    includes the basic steps involved.  This is what it takes to change an element 
//    tag name using DOM, it's much more involved using SAX.  
-------------------------------------------------------
// 1. create a new node with the desired tag name 
// 2. preserve old value to copy later 
// 3. move all children of current node to new node 
// 4. get parent of current node and replaceChild the current node with the new node 
// 5. copy old value or new value to new node 
// NOTE: Attributes are handled differently! 

// This is how to add a new attribute using DOM 
MSXML::IXMLDOMNamedNodeMapPtr pAttrList = m_pCurNode->Getattributes();
_bstr_t bstrAttrName = (_bstr_t)(LPCTSTR)m_strName;
MSXML::IXMLDOMAttributePtr pNewAttr = m_pDOMDoc->createAttribute(bstrAttrName);
_bstr_t bstrAttrValue = (LPCTSTR)m_strValue;
pNewAttr->PutnodeValue((_variant_t)bstrAttrValue);
pAttrList->setNamedItem(pNewAttr);
// TODO: The user must first search to be sure the attribute name is unique, or your XML will be invalid! 
// One of the well-formedness constraints that the XML 1.0 specification lists is that no attribute name  
// may appear more than once in the same start tag or empty element tag.  DOM never deals with this issue. 
// XML is case sensitive, so attribute "Name" is different from attribute "name", some tools built into DOM 
// sure would have been useful - good thing we have the XMLFoundation. 
AddNodeToTree(pNewAttr, m_hCurItem);

New World Order

The square world is becoming part of history like the flat world. I remember back in the early 90's we tried to rid ourselves of the square world with something called "The Object Database". It was a great concept and the only reason square prevailed against it is because nobody could implement an Object Database that was fast enough. Who cares how clean the code is if the application is dysfunctional because it is too slow? This is why XMLFoundation is so performance oriented - that's what it takes to change the world. The clean code alone is not enough.

Now I'll explain how to accomplish the task of loading up your object with the information in the XML using a fully object oriented approach to data handling. Customer, Order, and LineItem are derived from XMLObject. They must implement 1 virtual method called MapMembers() that would look like this:

void Customer::MapXMLTagsToMembers()
{
    MapMember(&m_OrderList, Order::GetStaticTag());
    MapAttribute(&m_nCustomerID, "id");
    MapMember(&m_strName, "Name");
}
void Order::MapXMLTagsToMembers()
{
    MapAttribute(&m_nOrderID, "id");
    MapMember(&m_LineItemList, LineItem::GetStaticTag());
    MapMember(&m_strDate, "Date");    // can also be mapped to a date/time object
}

void LineItem::MapXMLTagsToMembers()
{
    MapAttribute(&m_nLineItemID, "id");
    MapMember(&m_strDesc, "Desc");
    MapMember(&m_strPrice, "Price");    
}

Now all the object assignment and creation code is summed up into this one line.

// This assigns ALL member variables and creates sub-objects. 
Customers.FromXML( pzXML )

If you had a trace statement in the constructor of the Order, you would see that it was called for every appearance of an Order in the XML.

Now suppose you wanted to manipulate some member variables then regenerate the XML: just assign your member variables normally then regenerate your XML - that's just as easy.

char *pzXML = Order.ToXML()

MapXMLTagsToMembers() defines everything needed for your objects to read or write XML as a base method. Without the XMLFoundation you would have to code all that looping and mapping 2 times if you wanted both reading and writing XML. Without the XMLFoundation you will have a larger maintenance issue if any XML document structure changes because you'll have to hunt through your looping and recursion routines to find the Element name to change. XMLFoundation provides countless other niceties such as mapping any number of XML tags to the same member, and conditional inclusion of members in the output XML based on tag name or the member state such as DIRTY indicating that the member was updated and you only want ToXML() to generate a delta of the data rather than the entire set. You can specify element order or have them output alphabetically. Common needs that can all be accomplished in 1 line of code rather than pages of code.

//The following code is so involved using DOM only the basic steps are described.
//This is what it takes to change an element tag name using XMLFoundation.
-------------------------------------------------------
// This is how backward compatibility is achieved when Element tag
// names change. For example, if m_nVersion is mapped to an Element
// named "VersionNumber" but you want all future protocols to refer to this 
// Element as to "ProtocolVersion". This is achieved by the following code:
// This allows either "VersionNumber" or "ProtocolVersion" to set the value of 
// m_nVersion, but always refers to it as "ProtocolVersion" while serializing XML.
MapMember(&m_nVersion,"VersionNumber");
MapMember(&m_nVersion,"ProtocolVersion");
SetMemberSerialize("VersionNumber", false );


// This is how to add a new attribute using XMLFoundation 
// if nUpdate=1 the attribute list will be searched and updated if there is an existing 
// attribute called [pzName]if not found or if nUpdate=0 the new attribute will be added.
void AddAttribute( const char * pzName, const char * pzValue, int nUpdate=0 );

It's fun to compare the differences between DOM and XMFoundation, but much of the functionality in the XMLFoundation cannot be compared to anything in DOM. For example, the XMLFoundation maintains a bit flag field for each member that it manages. These are the values that can be managed:

// The value does not sync with the original value set by the Object Factory
#define DATA_DIRTY 0x01 
// The member has been set by either the Object or the Object Factory.
#define DATA_NOT_NULL 0x02
// The member has been assigned a value from the Object Factory
#define DATA_CACHED 0x04
// The member has never been assigned a value, it is uninitialized
#define DATA_NULL 0x08 
// The member should be included in the xml serialization stream
#define DATA_SERIALIZE 0x10

The following interface uses some of the member state flags:

// When objects are populated from the XML stream, they have a state of
// Not dirty and Not null. When the members are assigned by the derived 
// class through SetMember() or SetMemberByTag() the state becomes dirty.
// When using the SetMember() or SetMemberByTag() there is no need to 
// setMemberDirty(), but if the derived class does direct assignments
// to members that should be serialized, setMemberDirty() should be called.
// if you ever want to serialize or track the state change only.
// Setting bDirty to 0 will clear the dirty flag for a member variable.
bool setMemberDirty(void *pAddressOfMemberToSet, int bDirty = 1);
bool setMemberDirty(char *pzTagNameOfMemberToSet, int bDirty = 1);

// true if the memory state does not sync with the 
// original value set by the Object Factory
bool isMemberDirty(void *pAddressOfMemberToCheck);
bool isMemberDirty(char *pzTagNameOfMemberToCheck);

// true if the member has never been assigned a value, it is uninitialized
bool isMemberNull(void *pAddressOfMemberToCheck);
bool isMemberNull(char *pzTagNameOfMemberToCheck);

// true if the member has been assigned a value from the Object Factory
bool isMemberCached(void *pAddressOfMemberToCheck);
bool isMemberCached(char *pzTagNameOfMemberToCheck);

XMLFoundation also has many options available during the creation of the XML. DOM has nothing that compares.

/////////////////////////////////////////////////////////////////////////////////////// 
// serialization flags for ToXML() 
//////////////////////////////////////////////////////////////////////////////////////// 
// Otherwise XML tags appear in the order they were mapped 
#define ORDER_MEMBERS_ALPHABETICALLY       0x01  
// deeply recurse without including dirty members 
#define RECURSE_OBJECTS_DEEP               0x02  
// includes any member with a state of DATA_CACHED 
#define INCLUDE_ALL_CACHED_MEMBERS         0x04  
#define EXCLUDE_SHORT_TERMINATION          0x08
// Do not serialize any data from MapAttribute() members 
#define EXCLUDE_MAPPED_ATTRIBUTES          0x10  
// Do not serialize attributes that came in via XML but were unmapped with MapAttribute() 
#define EXCLUDE_UNMAPPED_ATTRIBUTES        0x20  
// Adds the DOCTYPE to the beginning of the XML 
#define INCLUDE_DOCTYPE_DECLARATION        0x40  
// includes any member regardless of it's state 
#define FULL_SERIALIZE                     0x80  
// include OID's only 
#define USE_OBJECT_MARKERS                 0x100 
// more compact, faster, less human readable, The XML will have no Tabs, Carriage returns or Linefeeds 
#define NO_WHITESPACE                      0x200 
// do not include empty strings in XML 
#define NO_EMPTY_STRINGS                   0x400 
// do not include the ObjectDataHandler registered with setObjectDataHandler() 
#define EXCLUDE_OBJECT_VALUE               0x800

It also has a SAX like (but faster and far simpler) way to subscribe to notifications.

// When a tag is encounterted that does not have a MapMember() entry
// associated with it, this handler is called for the developer
// to supply an "on-the-fly" MemberDescriptor during the Factory process.
// This is useful for dynamic objects. 
virtual MemberDescriptor *HandleUnmappedMember( const char *pzTag );


// Generic Event Handler for custom object behavior. Abstract to reduce virtual method table
// -----------------------------------------------------------------------------------------
// nCase = "XMLAssign", (member tag, XML value, value len, null)
// when the FromXML() contains a value for a member set dirty by setMemberDirty()
// see MemberDescriptor::Set() in MemberDescriptor.cpp for details.
// nCase = "NonNumeric" (member tag, XML value, value len, null)
// when non-numeric XML data is mapped to an numeric only type.
// nCase = "EmptyString"(member tag, XML value, value len, null)
// when an empty("") value is assigned to a string, empty often differs from 'unknown' or 'unassigned'
// nCase = "ObjectUpdate" when OBJECT_UPDATE_NOTIFY is a set behavior flag. (oid, null, flags, pObjSrc)
// nCase = "MemberUpdate" when MEMBER_UPDATE_NOTIFY is a set behavior flag. (tag, value, valuelen, null)
virtual void *ObjectMessage( int nCase, char *pzArg1, char *pzArg2, unsigned int nArg3, void *pArg4)

Faster than Fast

The approach used by XMLFoundation is faster than SAX. Since the object factory and the XML tokenizer were built for each other they did some unusual tricks for each other. The tokenizer uses a unique approach to begin with. It's purely pointer based. Tokens are structures that point into the source XML, except for entities that get expanded into a special memory region. Tokens do not hold copies of any data. During object factorization it becomes necessary to have the token data in a null terminated string format. The big performance boosting hack is that to obtain null terminated strings, the tokenizer actually plunks a null down over the first byte past the end of the token data. It keeps track of the data it clobbers and restores it before parsing out the next token. There are no event calls that needlessly push data on the stack just to immediately pop it back off. Performance profilers showed that call stack pushes and pops were the single largest consumer of CPU cycles in the tokenization process. XMLFoundation eliminates them by "pulling" the data through a call to [void getToken(token *tok)], rather than the SAX approach that gets the data "pushed" into the application events with between 2 and 7 arguments depending on the token type. SAX would be the fastest approach if the XMLFoundation did not exist. The XMLFoundation is the only XML parser that uses this approach. It is non-standard, and not in compliance with W3C interfaces to an XML Parser - For our uses, It's better than any W3C standard.

I realize that the vast majority of people who use XMLFoundation would never care about these grungy technical details. To say that it is very fast is enough for most people, but I am also writing to the people at the Apache Foundation, and Microsoft, and IBM, W3C, and the many other people who have built their own XML Parser implementations. Fast is an understatement. Performance is a prevailing design pattern found throughout the XMLFoundation. For example the XMLObject class is carefully designed to add minimal CPU cycles during construction because it is to the XMLFoundation what CObject is to MFC. It has been carefully designed to add minimal entries to the virtual method table. In many cases virtual calls were consolidated for that purpose.

Object Factorization

The Object Factory is the part of the XMLFoundation that instantiates objects for you based on certain element tags in the source XML. It is based on the same principle as DECLARE_DYNCREATE() that allows MFC to instantiate CView derived classes for you. In the XMLFoundation it is called DECLARE_FACTORY(). The XMLFoundation uses this macro to instantiate COM and CORBA objects as well.

Every object that derives from XMLObject must have 1 macro in the class definition, the DECLARE macro, normally in your .h source file. It must also have one macro at global space, often in the .cpp file matching the .h file - or you may choose to consolidate all of your IMPLEMENT macros in a single .cpp file. These macro's supply the XML tag and 'this' object's name, aka the class name. Terminology Note: Within the XMLFoundation the term 'tag' is 'Element Name' and sometimes 'Attribute Name'.

These macros write a method that return new instances of 'this' object type. The address of this global static function is stored in a structure keyed by tag name. As the tags are encountered - during the xml parsing - objects are created to contain the data that they expect to follow.

If a tag is mapped to an object in a list or tree structure, then every time that tag is encountered at the level it is mapped it will create a new instance for you and put it in the data structure (list, tree, etc.) you specified with all its member variables already assigned from the source XML as you have them mapped.

Member Mapping

XMLFoundation has support for mapping to all native C++ data types. It also has support for mapping into data container objects. It has specific support for RWCString, CString, and GString, and it's very easy to add support for others by deriving from the class "StringAbstraction" and supplying the pure virtual methods that will enable any kind of data container class to interoperate with the Object Factory for automatic member assignments. These are the MemberMap methods in XMLObject:

// Map an int / long int / or very long int 
void MapMember(int *pValue,const char *pTag);
void MapMember(long *pValue,const char *pTag);
void MapMember(__int64 *pValue, const char *pTag);

// Map a string, see StringAbstraction.h for interface and samples 
void MapMember(void *pValue,const char *pTag,StringAbstraction *pHandler);

// Map an object into a hash table, binary tree, or QSort array 
void MapMember(void *pDataStructure,
                 KeyedDataStructureAbstraction *pHandler,
                 const char *pzObjectName,
                 const char *pNestedInTag = 0);

// Map a collection of Strings 
void MapMember(void *pStringCollection,     const char *pzElementName,
                 StringCollectionAbstraction *pHandler,
                 const char *pNestedInTag = 0);

// Map a dynamically growing Integer array 
void MapMember(void *pIntegerArray,     const char *pzElementName,
                 IntegerArrayAbstraction *pHandler,
                 const char *pNestedInTag = 0);

// Map a sub-object using a tag other than defined in the DECLARE_Factory 
void MapMember(XMLObject *pObj,     const char *pDefaultTagOverride = 0, 
                                     const char *pzWrapper = 0 );
// Map a collection of Objects 
void MapMember(void *pList,const char *pObjectTag,
                 ListAbstraction *pHandler,const char *pNestedInTag = 0, 
                                             ObjectFactory pFactory = 0 );
// Map a sub-object pointer to an object residing in the ObjectCache 
void MapMember(XMLObject **pObj,const char *pzTag, 
                      const char *pNestedInTag= 0, ObjectFactory pFactory=0);

Inheritance of Mapping

The following code can be found in the example programs. Inheritance of XML maps works intuitively and enables you to organize and manage your code efficiently.

class CMatter : public XMLObject
{
public:
     GString m_strWeight;

 virtual void MapXMLTagsToMembers()
 {
   MapMember(&m_strWeight, "Weight");
   }
   DECLARE_FACTORY(CMatter, Matter)
   CMatter(){} 
   ~CMatter(){};
};
IMPLEMENT_FACTORY(CMatter, Matter)

//------------------------------------------------

class CLife : public 
<span style="background-color: rgb(255, 0, 0);">CMatter 
{
public:
GString m_strDNA;
virtual void MapXMLTagsToMembers()
{
   MapMember( &m_strDNA, "DNA");
   CMatter::MapXMLTagsToMembers(); // explicit base class call
}
DECLARE_FACTORY(CLife, Life) 
CLife(){ }
~CLife(){};
};
IMPLEMENT_FACTORY(CLife, Life)
//------------------------------------------------

class CHuman : public 
CLife
{
public:
GString m_strFingerPrint;
GString m_strGender;
   
virtual void MapXMLTagsToMembers()
{
     MapMember(&m_strFingerPrint,"FingerPrint");
     MapMember(&m_strGender,"Gender");
     CLife::MapXMLTagsToMembers(); // explicit base class call
}
DECLARE_FACTORY(CHuman, Human) 
CHuman(){} 
~CHuman(){};
};
IMPLEMENT_FACTORY(CHuman, Human)

//------------------------------------------------

char pzXML3[] = 
"<Human>"
"<Gender>Male</Gender>"
"<DNA>1101010001010101101011000010101010</DNA>"
"<FingerPrint>Unique</FingerPrint>"
"<Weight>777</Weight>"
"</Human>";


void Main()
{
   
CHuman O;
O.FromXMLX(pzXML3);

GString strDebug;
strDebug << "\n\n\nGender:" << O.m_strGender << " FingerPrint:" 
<< O.m_strFingerPrint << "\n" << "DNA:" << O.m_strDNA 

<< " Weight:" << O.m_strWeight << "\n\n";

   
printf(strDebug);
//////////////////////
// Gender:Male FingerPrint:Unique
// DNA:1101010001010101101011000010101010 Weight:777 
//////////////////////

  
printf(O.ToXML());
//////////////////////
//<Human>
// <FingerPrint>Unique</FingerPrint>
// <Gender>Male</Gender>
// <DNA>1101010001010101101011000010101010</DNA>
// <Weight>777</Weight>
//</Human> 
//////////////////////

CLife life;

//Notice that CLife is being created with pzXML3, 
//that is the same xml that the CHuman was created with.
life.FromXML(pzXML3);// Gender and FingerPrint are now unmapped data
strDebug.Empty();

strDebug << "\n\nDNA:" << life.m_strDNA << " " 
<< "Weight:" << life.m_strWeight << "\n\n";

printf(strDebug);
//////////////////////
// DNA:1101010001010101101011000010101010 Weight:777
//////////////////////

printf(life.ToXML());

//////////////////////
//<Life>
// <DNA>1101010001010101101011000010101010</DNA>
// <Weight>777</Weight>
//</Life>
//////////////////////

So- for example, you may create an object CPlant that like the CHuman is derived from CLife. A CPlant would contain the elements of CLife (DNA) and of CMatter (Weight) by inheritance.

If each XML message represents a transaction it is wise to map the commonalities of all transactions, or groups of transactions into a base class that allows derivatives to inherit the base elements of the transaction that will only be maintained in one place.

Object Model Navigation

By using the XMLFoundation you inherit some powerful navigation features that can be used to help you debug your application with the Dump() member. Because the factory manages all the object relationships, a new kind of object navigation arises: objects know their creators so an "Order" can know at runtime if it resides inside a list in a "Customer", or some other kind of object, or if it is not contained by another object at all. This is what a full Dump() output looks like:

----------------------------------------------------------------------------------
Object Dump                    My comments
----------------------------------------------------------------------------------
Object Instance name: MyOrder            Dump of Order Object
{
     string     OID = 
     string     UpdateTime = 
               References = 1                 
     --------------------------------
     Type  :string
     Tag   :OrderDate
     Value :1776-07-04                The Order Date is July 4 1776
     State :(Clean | Valid | Cached)
     Kind  :Element
     --------------------------------
     Type  :string
     Tag   :ShippedDate
     Value :2010-07-04                The Ship Date is July 4 2010
     State :(Clean | Valid | Cached)
     Kind  :Element
     --------------------------------
     Type  :List<XMLObject *>
     Tag   :LineItem                contains a list of 3 LineItem objects
     
     Contains:3 items
     Object Instance name: MyOrderLineItem
     {
          string     OID = 1121.0000            The 1st begins here
          string     UpdateTime = 
                    References = 26          
          --------------------------------
          Type  :string
          Tag   :Description
          Value :                    Description is empty
          State :(Clean | Null | Uncached)        here we can see that it was never
                                                assigned, it was not set to ""
          Kind  :Element
          --------------------------------
          Type  :int
          Tag   :ProductID
          Value :11                ProductID is 11
          State :(Clean | Valid | Cached)
          Kind  :Element
          --------------------------------
          Type  :string
          Tag   :UnitPrice
          Value :21.0000                Unit Price is 21.0000
          State :(Clean | Valid | Cached)
          Kind  :Element
     }
     Object Instance name: MyOrderLineItem        <--- here begins the 2nd of 3 line items
     {
          string     OID = 332.5000
          string     UpdateTime = 
                    References = 21          
          --------------------------------
          Type  :string
          Tag   :Description
          Value :
          State :(Clean | Null | Uncached)
          Kind  :Element
          --------------------------------
          Type  :int
          Tag   :ProductID
          Value :33
          State :(Clean | Valid | Cached)
          Kind  :Element
          --------------------------------
          Type  :string
          Tag   :UnitPrice
          Value :2.5000
          State :(Clean | Valid | Cached)
          Kind  :Element
     }
     Object Instance name: MyOrderLineItem
     {
          string     OID = 7234.8000
          string     UpdateTime = 
                    References = 23          
          --------------------------------
          Type  :string
          Tag   :Description
          Value :
          State :(Clean | Null | Uncached)
          Kind  :Element
          --------------------------------
          Type  :int
          Tag   :ProductID
          Value :72
          State :(Clean | Valid | Cached)
          Kind  :Element
          --------------------------------
          Type  :string
          Tag   :UnitPrice
          Value :34.8000
          State :(Clean | Valid | Cached)
          Kind  :Element
     }
}

GUI Objects

This is an example of what is involved to get XML to the GUI. The XML is somewhat complex to show how simple the code will be. The XML is a "Customer" with a list of "Orders" where each order has a list of "LineItems". This is the XML:

<Customer>
     <ContactName>New Dude</ContactName>
     <City>Antioch</City>
     <Country>All of them</Country>
     <Order>
          <ShippedDate>1997-09-02</ShippedDate>
          <OrderDate>1997-08-25</OrderDate>
          <LineItem>
               <UnitPrice>45.6000</UnitPrice>
               <ProductID>28</ProductID>
           <Description/>
          </LineItem>
          <LineItem>
               <UnitPrice>18.0000</UnitPrice>
               <ProductID>39</ProductID>
           <Description/>
          </LineItem>
     </Order>
     <Order>
          <ShippedDate>Futuristic</ShippedDate>
          <OrderDate>Tomorrow</OrderDate>
          <LineItem>
               <UnitPrice>1234567.77</UnitPrice>
               <ProductID>1234567</ProductID>
              <Description/>
          </LineItem>
     </Order>
</Customer>

Notice that the XML foundation will parse directly in to the CStrings that are already DDX bound to MFC's UpdateData(). This is accomplished through Multiple Inheritance. Our Dialog class derives from both MFC's CDialog, and XMLFoundation's XMLObject.

The sample application reads XML and displays it in the GUI where it can be changed by the user, then saved back out to XML that reflects the users changes.

The complete code for this example is in "XMLDialog", but for the purpose of understanding what it takes to integrate XMLFoundation with an MFC Dialog this shows you ALL the code of interest.

////////////////////////////////////////////////////////////// 
// Begin XMLDialog.h 
#include "xmlObject.h" 
#include "GList.h" 

class CXMLDialogDlg : public CDialog, public XMLObject
{
    //This is XMLFoundation releated code
     GList m_lstOrders;
     virtual void MapXMLTagsToMembers();
     virtual void *ObjectMessage( int nCase, char *pzArg1, char *pzArg2,
         unsigned int nArg3 = 0, void *pArg4 = 0 );
     DECLARE_FACTORY(CXMLDialogDlg, Customer);


    //This is code created by App Wizard
    //{{AFX_DATA(CXMLDialogDlg) 
     CString     m_strCity;
     CString     m_strCountry;
     CString     m_strName;
     CString     m_strRichEditXML;
     //}}AFX_DATA 
}

// End XMLDialog.h 
////////////////////////////////////////////////////////////// 
  


///////////////////////////////////////////////////////////// 
// Begin XMLDialog.cpp 
IMPLEMENT_FACTORY(CXMLDialogDlg,          Customer)

void CXMLDialogDlg::MapXMLTagsToMembers()
{
     MapMember(&m_strName,      "ContactName",           &gC);
     MapMember(&m_strCity,      "City",                  &gC);
     MapMember(&m_strCountry,   "Country",               &gC);
     MapMember(&m_lstOrders,    MyOrder::GetStaticTag(), &gGListHandler, 0 );
}

void CXMLDialogDlg::OnBtnMakeXML() 
{
     UpdateData(TRUE); // pickup the changes from the GUI into the member variables 
     m_strRichEditXML = ToXML();  // create the new XML 
     UpdateData(FALSE);           // display the new XML in the edit box 
}

void CXMLDialogDlg::OnBtnLoadGUI() 
{
     FromXML(m_strRichEditXML);  // parse the XML into 'this' 
     UpdateData(FALSE);// update everything on the GUI that AppWizard has a DDX map for 


     // note:UpdateData() does not push the list of 'Orders'[m_lstOrders] into the  
     // ListCtrl. The simplest way is to iterate [m_lstOrders] that contains the  
     // 'Orders' after the call to FromXML() is complete. 
     // This shows you the complex, SAXish like, way that will add 'Order' objects  
     // to the GUI as they are added to [m_lstOrders] by the Object Factory during  
     // the call to FromXML(). This requires adding some code to this's constructor:  
     // ModifyObjectBehavior(SUBOBJECT_UPDATE_NOTIFY);  
     // This causes the XMLFoundation to call ObjectMessage(), as each "Order" gets 
     // it's data from the XML.  This Actually adds data to the GUI DURING THE 
     // PARSING PROCESS, as opposed to the 'simplest' way that will add the data  
     // into the CListCtrl AFTER the parsing process.  


}


// The Order object is yellow, the complexity is CListCtrl, not the XMLFoundation. 
void *CXMLDialogDlg::ObjectMessage( int nCase, char *pzArg1, char *pzArg2, int nArg3, void *pArg4 )
{
     if(nCase == MSG_SUBOBJECT_UPDATE) 
     {
          MyOrder *pO = (MyOrder *)pArg4;
          int nItemIndex = m_List.InsertItem(LVIF_TEXT|LVIF_PARAM, 0, pO-&gt;m_strOrderDate, 
                                                                     0, 0, 0, (long)pO);
          m_List.SetItemText(nItemIndex, 1, pO-&gt;m_strShippedDate);

          // uncomment this to see that we can generate XML subsets very easily 
          //AfxMessageBox( pO-&gt;ToXML() ); // call base class method 
     }
     return 0;
}

CORBA Objects

The XMLFoundation was designed and built for CORBA before it ever added any support for MFC. If you have a pre-existing CORBA system that needs some XML tools you have come to the right place. If you are building a new CORBA system - this is best tool available for XML support.

If you have read this document all the way to this point then you will likely understand how the XMLFoundation works for CORBA by showing you this tiny piece of code:

class CustomerImpl : public virtual CustomerBOAImpl, public virtual XMLObject

along with the IMPLEMENT_ORB_FACTORY() macro defined in XMLObject.h, this is how CORBA can natively support the FromXML() and ToXML() by using the XMLFoundation. The Object Factory can instantiate your interface objects for you based on the XML.

CORBA implementations can be done in Java or C++. The XMLFoundation supports both. CORBA breaks down the language barrier allowing Java applications to easily, and natively deal with C++ objects. This example details the creation of C++ CORBA objects - The Java implementation is nearly identical further blurring the lines between Java/C++ within the same project.

The C++ CORBA implementation will bridge into J2EE Application servers everywhere, it will work for any ORB but a few of the most popular ones have been tested, and the makefiles are included with the CORBA sample that ships with the XMLFoundation. The three makefiles included are for:

  • Borland/Enterprise Studio - Visibroker
  • IONA/iPortal Enterprise - Orbix
  • BEA/Weblogic Enterprise - ObjectBroker (works great with Tuxedo implementations)

This example extends the ORB to provide native XML accessors. The sample CORBA application is based around 1 very simple object type. It has a unique integer we call a CustomerID and a string we call a CustomerName. Each customer may contain 0 to n references to another object of the same type as it's self, a MyCORBAObject. This would model something like a list of Customers that were referred by 'this' customer.

The IDL Looks Like This

module ExCORBA
{
 interface MyCORBAObject
 {
  void getXMLState(out string s);
  void setXMLState(in string s);
  void setState(in string s, in long l);
  void addSubObject(in string s, in long l);
  void delSubObjects();
  MyCORBAObject getSubObjectIOR(in long l);
  void dumpState(out string s);
 };
};

Follow this 12 Step Program

This is a very simple application. The client application makes 12 calls to the server. Every even numbered call is exactly the same - it is a call to getXMLState() to see what's going on in the server. The client obtains an initial IOR from a server serialized IOR upon server startup.

  1. Assign some state in a native CORBA call. This is a typical CORBA data assignment operation. Two values are set in the object. The client assigns two members on the server. The code looks like this on the client:
    CustObject1->setState("Root",777);
  2. View the state of the object in XML. This uses the XML accessor to return the state of the object. The code looks like this on the client:
  3. CORBA::String_var s;
    CustObject1->getXMLState(s);

    and looks like this on the server:

    void ExCORBAImpl::getXMLState( CORBA::String_out s)
    { 
      const char *p = ToXML();
      s = CORBA::string_dup(p);
    }

    and the result XML is this:

    <MyCORBAImpl>
       <CustomerID>777</CustomerID>
      <CustomerName>Root</CustomerName>
    </MyCORBAImpl>

    The tag names are configured by the ExCORBAImpl object like this:

    void  ExCORBAImpl::MapXMLTagsToMembers()
    {
        MapMember(&_nCustID, "CustomerID");
        MapMember(&_strCustName, "CustomerName",&gGenericStrHandler);
        MapMember(&m_lstCMyImplObjs, "MyCORBAImpl",&gGListHandler,0);
    }
  4. Update the state of the object through XML. Step 1 used a typical object accessor to assign the state. Step 3 accomplishes the same through XML. The code on the client looks like this:
  5. CustObject1->setXMLState("<MyCorbaImpl><CustomerName>SuperUser</CustomerName>
    </MyCorbaImpl>");

    On the server the code looks like this:

    void ExCORBAImpl::setXMLState( const char* pzXML ) 
    {
        FromXML( pzXML );
    }
  6. View the modified object state in XML. This is the exact same code (client and server) as Step 2. We're calling getXMLState() again, and the result is:
  7. <MyCORBAImpl>
       <CustomerID>777</CustomerID>
       <CustomerName>SuperUser</CustomerName>
    </MyCORBAImpl>
  8. Add CORBA Sub-Objects through XML. Step 5 is a lot like step 3 where we updated the name "root" to "SuperUser" through an XML assignment. This time we'll add an object reference. The client code looks like this:
  9. CustObject1->setXMLState(
     "<MyCORBAImpl>" 
           "<MyCORBAImpl>"
                 "<CustomerID>123</CustomerID>" 
                 "<CustomerName>Al Gore</CustomerName>" 
           "</MyCORBAImpl>"
           "<MyCORBAImpl>"
                 "<CustomerID>456</CustomerID>" 
                 "<CustomerName>George Bush Jr.</CustomerName>" 
           "</MyCORBAImpl>"
     "</MyCORBAImpl>");

    and this is the code on the server:

    void ExCORBAImpl::setXMLState( const char* pzXML ) 
    {
       FromXML( pzXML );
    }
  10. (exactly like steps 2 & 4) - View the object's XML state.
  11. <MyCORBAImpl>
       <CustomerID>777</CustomerID>
       <CustomerName>SuperUser</CustomerName>
       <MyCORBAImpl>
     
    <CustomerID>123</CustomerID>
     
    <CustomerName>Al Gore</CustomerName>
       </MyCORBAImpl>
       <MyCORBAImpl>
     
    <CustomerID>456</CustomerID>
     
    <CustomerName>George Bush Jr.</CustomerName>
       </MyCORBAImpl>
    </MyCORBAImpl>
  12. Get a CORBA object reference for object instance 456. On the client the code looks like this:
  13. ExCORBA::MyCORBAObject_var CustObject2;
    CustObject2 = CustObject1->getSubObjectIOR(456);

    and on the server we walk the list of objects and return the first one that matches the supplied CustomerID like this:

    ExCORBA::MyCORBAObject_ptr ExCORBAImpl::getSubObjectIOR(CORBA::Long CustomerID)
    {
      // create an iterator[it] for the [m_lstCMyImplObjs] list 
      GListIterator it(&m_lstCMyImplObjs);
      while(it()) // while there is more in the list 
      {
           XMLObject *pO = (XMLObject *)it++; // get the next Customer Interface 
           ExCORBAImpl*pIO = (ExCORBAImpl*)pO->GetInterfaceObject(); // widen the pointer 
           
            // test for a match - Use a keyed datastructure in the real world 
            if (pIO->GetCustomerID() == CustomerID)  
           {
                // Return the CORBA Interface to the desired object 
                  return pIO->_this();
                break;
           }
      }
      return 0;
    }
  14. Exactly like steps (2, 4 & 6) EXCEPT we are using the Object ref returned by step 7.
  15. <MyCORBAImpl>
      <CustomerID>456</CustomerID>
      <CustomerName>GeorgeBush Jr.</CustomerName>
    </MyCORBAImpl>
  16. Add a Sub-Object without using XML. In the same way we used a traditional member assignment in step 1, we can create a new object reference to demonstrate the two models seamlessly working together. On the client:
  17. CustObject1->addSubObject("Michelangelo",1475);

    and on the server the code looks like this:

    void ExCORBAImpl::addSubObject( const char* s, CORBA::Long l )
    {
       ExCORBAImpl *p = new ExCORBAImpl;
       p->_nCustID = l;
       p->_strCustName = s;
       m_lstCMyImplObjs.AddLast((XMLObject *)p);
    }
  18. Get an object reference to the object created in step 9 and display it's state in XML. This is the client code:
  19. CustObject2 = CustObject1->getSubObjectIOR(1475); // exactly like step 7 
    CustObject2->getXMLState(s); // like steps (2, 4, 6, and 8) using the new reference.

    and the result is:

    <MyCORBAImpl>
      <CustomerID>1475</CustomerID>
      <CustomerName>Michelangelo</CustomerName>
    </MyCORBAImpl>
  20. Deleting Sub objects. All objects, no matter how they were created, are destroyed the same. The list contains both Factory created objects and Objects created the tradional way. Once again this shows how seamlessly the ORB fits together with the XMLFoundations's Object Factory. This the CORBA Implementation/Interface and XMLObject are all one in the same. This cleans up the whole mess.
  21. CustObject1->delSubObjects();

    on the server:

    void ExCORBAImpl::delSubObjects() IT_THROW_DECL((CORBA::SystemException))
    {
       GListIterator it(&m_lstCMyImplObjs);
       while(it())
       {
             XMLObject *pO = (XMLObject *)it++;
             pO->DecRef();
       }
       m_lstCMyImplObjs.RemoveAll();
    }
  22. To see that step 11 worked, view the XML state like we did in 2,4,6,8, & 10. Now all the contained objects are gone, and "SuperUser" is alone.
  23. <MyCORBAImpl>
       <CustomerID>777</CustomerID>
       <CustomerName>SuperUser</CustomerName>
    </MyCORBAImpl>

COM Objects

Create a basic ATL COM project with Visual Studio.

Visual Studio will write your IDL, and implementation header files. The following code sample is the standard implementation header file with a few small additions (highlighted in yellow) required for XML support.

class ATL_NO_VTABLE CMyATLObj : 
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyATLObj, &CLSID_MyATLObj>,
public IDispatchImpl<IMyATLObj, &IID_IMyATLObj, &LIBID_EXATLCOMLib>,
public XMLObject
{
~CMyATLObj();
DECLARE_REGISTRY_RESOURCEID(IDR_MYATLOBJ)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMyATLObj)
COM_INTERFACE_ENTRY(IMyATLObj)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

void MapXMLTagsToMembers();

public:
DECLARE_FACTORY(CMyATLObj, Container)
};

In your implementation file you'll need to add the macro at a global scope and implement MapXMLTagsToMembers() to define the Object to XML mappings. This example maps an integer, a string, and a list of COM objects.

void
CMyATLObj::MapXMLTagsToMembers()
{
   MapObjectID("CustomerID",1);
   MapMember(&m_nInteger, "CustomerID");
   MapMember(&m_strString, "CustomerName", &gGenericStrHandler);
   MapMember(&m_lstCMyATLObj, CMyATLObj::GetStaticTag(),
&gGListHandler,0);
}

In the ExATLCOM sample application several additional methods have been added to the COM Object. Most notably put_XMLState() that has the ability to assign members variables and create COM objects when supplied well-formed XML as input.

STDMETHODIMP
CMyATLObj::put_XMLState(BSTR newVal)
{
     _bstr_t b(newVal);
     FromXML((const char *)b);
     return S_OK;
}

Object Caching and Instance Management

XMLFoundation has been serving up the XML related needs of the application layer for nearly a decade. It has been used to build a wide variety of application types. A common recurring need in the application layer has to do with "data updates". Any application that receives XML updates might consider the performance advantages and reduction in development labor by using the XMLFoundation to solve the problem for them.

For example, suppose you had some large dump of XML data. In your application layer you need to quickly access individual pieces of that information. In just a few lines of code, the XML can be mapped to a keyed data structure for fast indexed reads by your application. If the initial XML dataset was 100+million records - you will want to provide updates to your indexed information rather than rebuilding the entire index. You could write the code to search for the data to update, or allow the XMLFoundation to manage it for you.

Another common example in distributed systems: Data is often cached at a middle tier or in the application itself. Efficiently designed systems only update an "Address" rather than a whole "Customer" and all his "Orders" when an "Address" changes. XMLFoundation can greatly simplify this task.

At the core of caching is something XMLFoundation calls the OID, or Object ID. It is a unique key to the object, and any object that participates in XMLFoundation caching must have one. The definition of the OID can come from 2 places. It can be defined in the XML data, or it can be defined by the object that mapped the data.

This is how a "'MyOrderLineItem" object might define the OID. It uses a combination of the "ProductID" and "UnitPrice" so in this example a price change constitutes a different object. Normally an OID has a direct correlation to DBMS indexes in properly normalized data. ObjectID's can be made to work well over poor data models too. This example code uses two XML Elements ("ProductID" and "UnitPrice") to build the unique object ID. MapObjectID() also allows you to use Attributes to define the OID.

void MyOrderLineItem::MapXMLTagsToMembers()
{
     MapObjectID("ProductID",1,"UnitPrice",1);
}

Alternatively the OID can be directly defined by the data itself with a special attribute named "OID" - so that NO CODE needs to be written.

<MyOrderLineItem oid='777'>
     <ProductID>123</ProductID>
     <UnitPrice>7.77</UnitPrice>
</MyOrderLineItem>

The sample application "ObjectCache" provides over 30 test cases that detail the usage of object caching.

Parsed and Unparsed Object Data

For the most part - objects contain members. Members are mapped to attributes and elements in the XML. For the most part - that is how most XML documents are arranged but as you will see here there are yet still two other forms of markup for getting untagged data into the object. As a prerequisite to reading the following paragraph you must know a little bit about what the XML specification refers to as CDATA, so go plug that into your favorite search engine if you are not familiar with unparsed data then when you pop your stack of things to do you will find yourself ready to continue reading this:

<Thing Color='Red White and Blue'>

     <![CDATA[<data>x</data>]]>-Object Data-=            
<---Pay special attention to this line

     <String>Capitol Capital G</String>

     <Number>777</Number>

     <Wrapper>
              <StringList>one</StringList>
              <StringList>two</StringList>
     </Wrapper>=-More Object Data- 
<---and this line  (Parsed Data)

</Thing>

The class declaration below has Maps for all of the elements and attributes in the XML above. It makes no provisions for Object Data - Parsed or Unparsed.

class MyCustomObject : public XMLObject
{
public:

     GString m_strString; // A String Member
     GString m_strColor; // An attribute , not an element
     int m_nInteger; // An Integer Member
     GStringList m_strList; // A String List


virtual void MapXMLTagsToMembers()
{
     MapMember( &m_strList, "StringList", "Wrapper");
     MapMember( &m_nInteger, "Number");
     MapMember( &m_strString, "String");
     MapAttribute(&m_strColor, "Color");
}

DECLARE_FACTORY(MyCustomObject, Thing) 

MyCustomObject(){} 

    ~MyCustomObject(){};

};

IMPLEMENT_FACTORY(MyCustomObject, Thing)

This is how your code will obtain this "unmapped" object data.

void ObjectDataAndCDataExample()
{
    MyCustomObject O;
    O.FromXMLX(pzXML);

    GString *pG = O.GetCDataStorage();
    printf(*pG); // prints out "<data>x</data>"
    printf("\n\n"); 

    // Notice that the memory address of the (unparsed)CDATA start is 43 bytes past &pzXML[0]
    // This CDATA buffer will always be in the original memory, not a copy of that buffer.
    // This unparsed data from the XML is handed directly to the application layer.
    int nOffsetFromStartofXML = pG->Buf() - pzXML; // nOffsetFromStartofXML is 43


    pG = O.GetObjectDataStorage();
    // you can see by this offset that we are in a different memory region now 
    // (because the fragmented Object data is now contigous)
    nOffsetFromStartofXML = pG->Buf() - pzXML; // nOffsetFromStartofXML is way out there.
    printf(*pG); // prints out "-Object Data-==-More Object Data-"
    printf("\n\n");

    // notice that the 'normal' data mapped to String, StringList, and Int 
    // are in the members and data structures where they have been mapped to.
    // Notice how the Object Data is rearranged in the output to a lexically equal notation.
    // Also notice that no whitespace (carriage returns or tabs) can be used to beautify this ugly Object Data
    // or it would alter the data, unlike the whitespace added between XML element tags to beautify them.
    // If Object Data has a Carriage Return in it, that is part of the data.
    printf(O.ToXML());
    printf("\n\n");

/*

<Thing Color="Red White and Blue">
     <![CDATA[<data>x</data>]]>-Object Data-==-More Object Data-
     <Wrapper>
          <StringList>one</StringList>
          <StringList>two</StringList>
     </Wrapper>
     <Number>777</Number>
     <String>Words</String>
</Thing>

*/
// ------------------------------

// now inversely, from a fresh object O2, make the xml
MyCustomObject O2;
O2.m_nInteger = 777;
O2.m_strString = "G.G.G.Guru";
O2.m_strColor = "Gold, Green and White";

*(O2.GetCDataStorage()) << "x<data>x";
// notice how this CData is not parsed

O2.SetObjectDataValue("-- object <data> is parsed --");         
//  and how the object data is parsed
// when they are turned into XML
printf(O2.ToXML());


/* // it looks like this:
<Thing Color="Gold, Green and White"> 
     <![CDATA[x<data>x]]>-- object &#60;data&#62; is parsed -- 
     <Number>777</Number>
     <String>G.G.G.Guru</String>
</Thing>

*/

}

FiveLoaves (aka ServerCore)

5Loaves is included with the XMLFoundation, but not in the foundation. It is a tool that uses XMLFoundation. It needs the XMLFoundation but the XMLFoundation does not need 5Loaves. 5Loaves is implemented in a single file called ServerCore.cpp. It is a unique piece of code and it is very simple to use. There is no header file for ServerCore.cpp and it causes no DLL's to be loaded by your application. It is a portable, properly threaded, and well written server core that can be applied to countless custom server implementations. It is a Proxy. It is an HTTP Server. It is a 'connection joiner'. ServerCore.cpp is currently used to accept TCP connections for an advanced networking product called Xfer. (note: Xfer is not open source). The ServerCore has a good portable threading model with some unique features that allow you to limit such things as, number of connections per IP/Subnet and Connections per second. The 5Loaves HTTP Server works faster than IIS or Apache in some cases. It has been designed to be fast and includes unique features such as 'content caching' to serve up prebuilt HTTP headers and data from memory rather than from disk.

The Core of 5Loaves is a ground up POSIX threaded TCP server. This server template can be applied to build many types of applications that service TCP connections. The sample programs are server applications that use the 5Loaves ServerCore. One example is the 5Loaves shell console. It is a command line interpreter like the DOS prompt or a Unix shell written from scratch. It is a useful application starting point if you ever need a simple shell that has been tested in Linux, Solaris, AIX, HPUX, and Windows. There is also a Windows Service application. It contains the proper implementation for integrating 5Loaves with the Windows Service Control Manager. There is also an example program with all the source to an ActiveX implementation of 5Loaves so you can see that this server core can be embed just about anywhere in any development language.

The following code sample shows you how to start the HTTP service from inside your own process. You can't do that with IIS or Apache. The HTTP server does support binary plugins like ISAPI, and there is an example program that creates plugins. It's an advanced HTTP server.

// This is a complete source example to embed a solid and high performance
// HTTP Server in your application that starts on a variable port with a
// variable home directory.
#include "../Core/ServerCore.cpp"


char *pzBoundStartupConfig =
"[System]\r\n"                // <-- notice the [System] section
"Pool=20\r\n"
"ProxyPool=0\r\n"
"\r\n"
"[HTTP]\r\n"                // <-- notice the [HTTP] section
"Enable=yes\r\n"
"Index=Index.html\r\n"
"Home=%s\r\n"
"Port=%s\r\n";

void CMyClass::StartHTTPServer(const char *pzHomeDirectory,const char *pzPort)
{
     // Fill the two variables into the startup config string
     GString strCfgData;
     strCfgData.Format(pzBoundStartupConfig,pzHomeDirectory,pzPort);
          
     // Set the global profile object
     SetProfile(new GProfile( strCfgData, strCfgData.Length()) );
     
     // Start the HTTP service
     server_start();

Building a Custom HTTP Web Service

Approach #1 - "Low Level Static Code"

Adding on to the rather trivial amount of code shown above for integrating ServerCore, you may want to develop a custom "dynamic content" server based on this HTTP server implementation that can be easily integrated into YOUR process (unlike IIS or Apache). There are several ways to go about accomplishing this task and depending on your situation one way may be more appropriate than another. One way of implementing a custom ServerCore extension can be accomplished via "Low Level Static Code". The advantage to this form of integration is that no DLL's are loaded. Another possible advantage is that no form of integration could possibly be faster. Using this approach ServerCore will manage nothing except for multi-threading the connections for you and the initial TCP network read.

This can be done by adding this one line of code:

#define SERVERCORE_CUSTOM_HTTP

prior to adding this line of code:

         #include "../Core/ServerCore.cpp"

You will also have to create a file called ServerCoreCustomHTTP.cpp, a sample implementation has been provided in the Server/Core folder. To see it work in the "5Loaves" example project add the #define SERVERCORE_CUSTOM_HTTP into the file Servers/5loaves/Console.cpp then create a text file called 5Loaves.txt that you can place in the same folder as the binary or at "C:\\" with this contents.

[System]
Pool=20
ProxyPool=0


[HTTP]
Enable=yes

This sets the thread pool to 20 setting the limit of your server to 20 concurrent client connections and supports no proxy connections, you may set the thread pool at any value that you have enough hardware resources to support.

Making this example work in the Windows Service is equally as simple by adding #define SERVERCORE_CUSTOM_HTTP into Servers/WebServerService/WebServerService.cpp (directly above the inclusion of ServerCore.cpp) This will extend the service application to run a custom 'low level - static code' extension that is implemented in ServerCoreCustomHTTP.cpp exactly like the console application.

I have two products that both use this "Low Level Static Code" approach to extending ServerCore.cpp. It is my preferred approach when building an "application" based on ServerCore.cpp because the integration is "tight" beyond the definition of "tight". You should search ServerCore.cpp for SERVERCORE_CUSTOM_HTTP to see for yourself that this is not function call - but a true inline implementation into the very first call stack frame of the servicing thread. Since the code is being added directly into the lowest level possible there is no function call dispatch, it executes the extension without even adding a new frame on the call stack (you can't do that with IIS or Apache - much less in YOUR process space) - this makes the extension code look strange because there will be no open scope { or close of scope } - and you will exit with a GOTO rather than a return. For example consider this complete example found in Servers/Core/ServerCoreCustomHTTP.cpp:

//
// Server Core Extension Example for when SERVERCORE_CUSTOM_HTTP is defined in ServerCore.cpp
//

// There are many variables available to the current scope.  A few of exceptional interest are:
// [td->sockfd] the socket handle
// [sockBuffer] the raw network data directly in the TCP kernel buffer
// [nContentLen] the Content-Length from the HTTP header
// [nBytes] bytes in [sockBuffer] (note there may be more in transit if Content-Length > nBytes )
if (memcmp(sockBuffer,"GET",3) == 0)
{
   
     GString strRequest;
     // extract the file name starting at the 4th byte up to the first space
     // Proper HTTP will look like this:GET /Index.html HTTP/1.1
     strRequest.SetFromUpTo(&sockBuffer[4]," ");

     // now you have the request in the variable [strRequest]

     // you need to generate a response for yourself based on the request.
     // This is a good place to dispatch your call to your own functions
     // You might return HTML, or XML
     GString strResponse("Server Response: Hello World");
   
     // since we did not build any custom HTTP headers we'll send the response back through HTTPSend()
     // This will build the HTTP headers for us setting the Content-Length - required for valid HTTP.
     HTTPSend(td->sockfd, strResponse, strResponse.Length());

     // alternatively we could setup the HTTP header ourselves and call nonblocksend()
     // int nonblocksend(int fd,const char *pData,int nDataLen)

     // lastly - manage this connection and thread.
     // this will read the next HTTP command from this connection - on this thread
     goto KEEP_ALIVE;

     // alternatively we could close this connection and return this thread to the pool
     // nCloseCode = 7000;
     // goto SOCKET_ERR_ABORT;

}
else if (memcmp(sockBuffer,"POST /",6) == 0)
{
     // likewise the same ideals apply for a POST handler
}

Now - to see this example work... Run 5Loaves.exe with the 5Loaves.txt in the same directory Put this URL into your browser: http://127.0.0.1/ Your browser will display "Server Response: Hello World"

Approach #2 - "Binary Plugin"

This next approach to extending an HTTP service is more typical. Both IIS and Apache support both CGI and ISAPI to support user developed web server extensions via "Binary Plugin's". This approach allows you to rebuild the extension without rebuilding the HTTP server. You will create a DLL (under Windows) or an SO (under Unix) that works a lot like ISAPI. The HTTP service will load and execute your extension giving you access to everything necessary to build any kind of custom extension. The ServerCore adds one additional layer of abstraction by invoking the "Plugin" through the "Language Driver" described in the next section.

Plugins and Language Drivers

The XMLFoundation supports "Language Drivers". 5Loaves is among the applications that implements them. Language drivers allow user developed extensions to be invoked programmatically. Just about every programming language can have a language driver developed for it. Several complete Language Driver implementations come with the XMLFoundation source code.

The programmer's code is "the plugin" that is executed by the "Language Driver". The majority of people who use this technology will probably be developing "plugins", but you also may develop an application that allows users to develop their own plugins. All of the source code for everything I speak of is included in the XMLFoundation, see [IntegrationBase.h/cpp][IntegrationLanguages.h/cpp], using DynamicLibrary.h to load the DLL/SO's on many platforms.

I have used the Language Driver functionality in several applications. For example, I have an XSLT that allows user extensions in addition to the built-in XSL keywords. This allows my application to pass a string value into a user defined method in a plugin that might need to do a database lookup to translate a code - a task that is too complex for any XSL keyword. Loading the "Language Driver" and executing a plugin does not require much code. This is the code to pack 4 arguments and invoke a plugin called "Test1" inside "PluginExample.dll" through the CStdCall Language Driver:

// pack 4 arguments -- same code to call (C++/Java/COM/Perl/Python) plugins
 // 1. a 4 bytes string ("aaa" + null)
 // 2. a 4 byte string  ("bbb" + null)
 // 3. a 4 byte unsigned long (the .... starts at the 8th byte and will be overwritten)
 // 4. a 5 byte string  ("fast" + null)
 char pzArgBuff[256];
 sprintf(pzArgBuff,"aaa%cbbb%c....fast%c",0,0,0);  // the .... is a 4 byte placeholder
 unsigned long *pL = (unsigned long *)&pzArgBuff[8]; // get an int pointer to the 8th byte
 *pL = 777;     // overwrite the (....) with the packed binary value for 777
 char pzArgSizes[16];
 strcpy(pzArgSizes,"4|4|4|5");

 // Invoke the plugin....
 InterfaceInstance *pII = GetInterfaceInstance("CStdCall");
 // InvokeEx may modify the pzArgBuff, but generally results should be in pzResults
 int nOutResultSize;
 const char *pzResults = pII->InvokeEx( "PluginExample.dll", "PluginExample", "Test1",
                                           pzArgBuff,pzArgSizes,&nOutResultSize, "anonymous",
                                           "password" );

The code shown above would be in the hosting application, or the application that supports custom extensions. It will then execute the plugin that is even easier to develop (code shown below):

ExposedMethods() should define the arguments like this:
Test1&&One&&char *&&Two&&char  *&&Three&&Packed Unsigned Long&&Four&&char *
extern "C" __declspec(dllexport) void Test1(void *pHandle, DriverExec Exec,
                                                const char *One,     // string "aaa"
                                              const char *Two,     // string "bbb"
                                              const char *Three,   // unsigned long
                                              const char *Four)    // string "fast"

{
     PlugInController PIC(pHandle, Exec);

     // dereference Three and increment it by one, this changes
     // the argument value in the callers memory space in the application -
     // (pzArgBuf above setting *pL to 778)
     // The direct memory reference is passed into the language driver -
     // then passed into this DLL/SO
     (*(unsigned long *)Three)++;

     // If you want to modify the argument Three locally use this code:
      unsigned long uThree = *(unsigned long *)Three);
      uThree++;
      PIC.AppendResults("Argument 3 is Native Packed Binary in a Plugin");
}

One sample application titled "PluginExample" is devoted to C++ plugins. It shows how to write several types of POST handler plugins for the HTTP server. You will find the utility class CMultiPartForm handy if you need to write a handler for a Multipart HTTP POST, other plugin utilities like PlugInController found in PluginBuilder.h make the job of building a plugin as easy as possible.

ServerCore.cpp has the implementation using (InterfaceInstance *)pII->InvokeEx()described above already complete so that you may extend the HTTP service via your own DLL(or COM object or Perl/Python script). This is how to build a custom dynamic web page from an HTTP server plugin:

  1. Compile the CStdCall Language Driver
  2. Compile the PluginExample
  3. Setup the 5Loaves.txt Configuration File like this (but set the [TXML]Drivers= and [CStdCall]Path= to where steps 1 and 2 compiled to):
    [System]
    Pool=20
    ProxyPool=0
    
    [HTTP]
    Enable=yes
    EnableServerExtensions=yes
    ServerPlugin1=/Test2WWWPage|CStdCall|PluginExample.dll|PluginExample|Test2
    ServerPlugin2=/Test3WWWPage|CStdCall|PluginExample.dll|PluginExample|Test3
    ServerPlugin3=/Test4WWWPage|CStdCall|PluginExample.dll|PluginExample|Test4
    ServerPlugin4=/Test5WWWPage|CStdCall|PluginExample.dll|PluginExample|Test5
    ServerPlugin5=/Test7WWWPage|CStdCall|PluginExample.dll|PluginExample|Test7
    ServerPlugin6=/Page1|CStdCall|PluginExample.dll|PluginExample|Page1
    ServerPlugin7=/Page2|CStdCall|PluginExample.dll|PluginExample|Page2
    ServerPlugin8=/Page3|CStdCall|PluginExample.dll|PluginExample|Page3
    
    [TXML]
    Drivers=C:\XMLFoundation\Drivers\Debug
    
    [CStdCall]
    Path=C:\XMLFoundation\Examples\C++\HTTP.Xfer.Messaging-PluginExample

    The HTTP service will loop through the ServerPluginN entries and dispatch the plugin calls for you. You must configure the ServerPluginN entries in numerical order and the HTTP service will load each entry upto the first numerical break. You may also manage the dispatch partially yourself by using a wildcard * in the first argument - for example.

    ServerPlugin1=/PluginPage*|CStdCall|MyDLL.dll|MyDLL|DoIt

    This would map the following URL's to DoIt() in:

    MyDLL.dll
    http://127.0.0.1/PluginPageFoo.html
    http://127.0.0.1/PluginPageBar%20Argument1%20Argument2
    http://127.0.0.1/PluginPageHello
  4. Put the 5Loaves.txt file into the project directory if you run 5Loaves.exe under a debugger or put 5Loaves.txt in the same directory as 5Loaves.exe if you run 5Loaves.exe outside the debugger - either way when it starts 5Loaves will display this message:
  5. 5Loaves>Windows Console using [5Loaves.txt]
    Listening on port[80]
    All bound ports are now being serviced
    started
    
    5Loaves>
  6. Now execute the most basic plugin that takes 0 arguments and is simply a static bound html page - put this URL into your browser: http://127.0.0.1/Page1
  7. The browser will show a simple web page with 3 edit fields and a "Submit" button. If you see that page - the plugin executed properly through an HTTP GET which loaded an HTML page that will POST back the 3 arguments into another handler that exists in that same plugin. The information POST'ed by the HTML form calls a method with with 3 arguments. So you supply the values 1, 2, and 3 to the three edit fields and press submit your browser will display this:

    5Loaves HTTP Server Invoked me with [1] and [2] and [3]!
  8. Now try this URL: http://127.0.0.1/test2WWWPage&root&777&superuser and this will be the result:
  9. 5Loaves HTTP Server Invoked me with [root] and [777] and [superuser]!
  10. Look at the Plugin example to see the details of implementing a plugin. You will see that this is the plugin handler that was called in step 5 and 6:
  11. extern "C" __declspec(dllexport) void Test2(void *pHandle, DriverExec Exec,
                                                          const char *One,     // string
                                                           const char *Two,    // string
                                                           const char *Three)  // string
    
    {
         PlugInController PIC(pHandle, Exec);
       
         // build the string "5Loaves Invoked me with [root] and [777] and [superuser]!"
    
         PIC.AppendResults("5Loaves HTTP Server Invoked me with [");
         PIC.AppendResults(One);
         PIC.AppendResults("] and [");
         PIC.AppendResults(Two);
         PIC.AppendResults("] and [");
         PIC.AppendResults(Three);
         PIC.AppendResults("]!");
    }

FiveLoaves Tunneling and Messaging

5Loaves provides tunneling with encryption and compression as a base service. It can be used to secure internet connections much like SSH. It works by running some form of server with the 5Loaves engine on two machines. The data passed between those machines can be compressed or encrypted or simply logged. Starting the server is done exactly the same no matter if you are running the HTTP service or the Tunneling service - only the configuration startup string changes. The following configuration example will open a listener on port 1972, anything it receives will be encrypted and compressed and sent to [www.ExampleServer.com] on port 2009. The server will decrypt and decompress the data from port 2009 and forward it to port 1972, so the data on port 1972 at the server will be as if the client had directly sent it. To open a tunnel entry point on the client side use this:

[Tunnel1]
Enable=yes
LocalPort=1972
RemotePort=2009
RemoteMachine=www.ExampleServer.com
Timeout=30
CompressEnabled=yes
CipherPass=Tiger
RawPacketProxy=no

To exit the tunnel on the server:

[Proxy1]
Enable=yes
LocalPort=2009
RemotePort=1972
RemoteMachine=127.0.0.1  (we could also use an internal resource like
192.168.*)
Timeout=60
RawPacketProxy=no
CompressEnabled=yes
CipherPass=Tiger

Note: you can start any number of tunnels, simply increment the section [Tunnel2] and [Proxy2]. ServerCore will stop loading tunnels at the first break of numeric order of the [sectionN].

This type of usage may be of interest especially to web developers or people who are just curious. Sometimes it's interesting to see the data between the HTTP server and the browser. Redirects and HTML frames and Javascript can make that difficult. This section sets up a clear text proxy just for the purpose of seeing the transmission log between the browser and the web-server. Once this is running, connect with a web browser to 127.0.0.1 and you in fact be connecting to the endpoint configured under the RemoteMachine= entry.

[Tunnel2]
Enable=yes
LocalPort=80
RemotePort=80
RemoteMachine=www.SampleWebSite.com
Timeout=65000
RawPacketProxy=yes
LogPath=c:\HTMLSpy
LogBinary=no
LogEnabled=yes

In the folder HTMLSpy you will see a log file of the communication between the browser and the web server. I used Firefox as a browser, and the 5Loaves HTTP server for this example. I loaded the page twice in the browser so that you can see the caching mechanism working between the browser and the web server in this log file: The header is defined like this: "tx->s" means "transmit to server" so that is information that came from the browser, it is followed by the time, then the total bytes transmitted, 470 in this case. The reply is "tx->c" or "transmit to client", you can see that the HTTP server responded with 181 bytes that instructed the browser to use the version it has cached. You can also see that the "Server:" name was set to "MyWebServer", that is a variable in the 5Loaves HTTP server unlike the static names IIS and Apache use.

tx->s00:51:42-000470>
GET / HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.11)
Gecko/2009060215 Firefox/3.0.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
If-Modified-Since: Thu, 01 Jan 1970 00:00:00 GMT
If-None-Match: 7430174881
Cache-Control: max-age=0


tx->c00:51:42-000181>
HTTP/1.1 304 Not Modified
Server: MyWebServer
Date: Sun, 16 Aug 2009 07:01:12 GMT
Connection: keep-alive
Keep-Alive: timeout=20, max=149
ETag: 7430174881
Content-Length: 0

By changing the log binary to yes, now we can see what a small gif file looks like over the wire from the web server.

[Tunnel2]
LogBinary=yes

tx->c01:05:29-000317>
48 54 54 50 2F 31 2E 31 20 32 30 30 20 4F 4B 0D 0A 44 61 74 65 3A 20 57
65      HTTP/1.1 200 OK..Date: We
64 2C 20 30 31 20 4A 75 6C 20 32 30 30 39 20 30 31 3A 30 35 3A 32 39 20
47      d, 01 Jul 2009 01:05:29 G
4D 54 0D 0A 53 65 72 76 65 72 3A 20 4D 79 57 65 62 53 65 72 76 65 72 0D
0A      MT..Server: MyWebServer..
43 6F 6E 6E 65 63 74 69 6F 6E 3A 20 6B 65 65 70 2D 61 6C 69 76 65 0D 0A
4B      Connection: keep-alive..K
65 65 70 2D 41 6C 69 76 65 3A 20 74 69 6D 65 6F 75 74 3D 32 30 2C 20 6D
61      eep-Alive: timeout=20, ma
78 3D 31 34 39 0D 0A 4C 61 73 74 2D 6D 6F 64 69 66 69 65 64 3A 20 53 75
6E      x=149..Last-modified: Sun
2C 20 31 33 20 4D 61 72 20 32 30 30 35 20 32 32 3A 33 32 3A 33 36 20 47
4D      , 13 Mar 2005 22:32:36 GM
54 0D 0A 45 54 61 67 3A 20 31 31 31 30 37 34 39 35 35 36 0D 0A 43 6F 6E
74      T..ETag: 1110749556..Cont
65 6E 74 2D 74 79 70 65 3A 20 69 6D 61 67 65 2F 67 69 66 0D 0A 43 6F 6E
74      ent-type: image/gif..Cont
65 6E 74 2D 6C 65 6E 67 74 68 3A 20 37 34 0D 0A 0D 0A 47 49 46 38 39 61
10      ent-length: 74....GIF89a.
00 10 00 91 00 00 00 00 00 FF FF FF FF FF FF 00 00 00 21 F9 04 01 00 00
02      ..................!......
00 2C 00 00 00 00 10 00 10 00 00 02 1B 94 8F A9 CB 07 AD C0 83 4E 52 23
2D      .,...................NR#-
CD BA F1 BE 7C 5B 76 91 E5 54 5E EA CA 1A 05 00
3B                           
....|[v..T^.....;

Messaging

5loaves has a unique network connectivity utility built in. It allows machines behind a firewall that cannot "listen" for connections outside the network to accept connections from anywhere without any firewall configuration changes. There is a complete example called "FilePoster" that puts a file on a machine behind a firewall. This is a bare bones 'proof of concept' implementation that gives you a working model to customize for your own purposes. It requires 3 machines to see it work as designed.

Machine 1 - (the switchboard) should be located on the internet. You must run the HTTP service along with the "Switchboard Service", you can see that this example runs it on port 81 just incase you have IIS or Apache already on port 80.

[SwitchBoardServer]
Enable=yes
Name=/PublicPath/

[HTTP]
Enable=yes
Port=81
ContentCache=0
UseKeepAlives=1
HTTPHeaderServerName=5Loaves
KeepAliveTimeOut=20
ShowIPAddressPageName=ShowIP
Home=d:\home


[Trace]
HTTPHeaderTrace=0
ThreadTrace=0
ConnectTrace=1

Machine 2 - (the server) this is the machine behind the firewall that you want to open up a connection path to. It will poll the switchboard server looking for connections. It should run 5oaves with the configuration below. This will accept remote data, and write it to disk in a file at "c:\5LMessages\UBTsAccountForYou". You could change the application logic that writes the file - you can do anything with the data that may contain commands, database queries, or custom logic.

[Messaging]
Enable=yes
AcceptFrom=UBTsAccountForYou
DefaultSwitchBoardServer=10.20.30.40
DefaultSwitchBoardPort=81
UseBrowserProxy=no


[MsgFrom-UBTsAccountForYou]
Enable=yes
CheckAtSwitchBoard=yes
Name=/PublicPath/UBTsAccountForYou
DiskLocation=c:\5LMessages\UBTsAccountForYou
LetSenderPlaceFile=No
PollIntervalSeconds=20

Machine 3- (the client) runs the FilePoster sample application. Machine 3 can reach "the switchboard (machine 1)" but not "the server (machine 2)". We will send the data to Machine 2 and get a response back from that machine. In this case we are simply writing the data we send to a file, but the data could just as easily have been an SQL statement and the return data could be the result set rather than just a confirmation that the file was written.

How it works:

The "server" polls into the "switchboard" with an HTTP GET. The "client" pushes a multipart HTTP POST to the "switchboard". The switchboard joins the connections and proxies the data. An HTTP GET needs an HTTP "200 OK" so the "switchboard" server rips off the POST headers from the data sent up by the "client" and replaces them with an HTTP 200 followed by the POST data that gets proxied straight through. Once this initial message proxy is complete, the client connection that POSTed it waits in the switchboard, for the server to POST back a response. Then the Switchboard goes through the same process of ripping off the POST HTTP header and replacing it with a 200 OK before sending the response back to the client. Lastly, the switchboard server replies with an empty HTTP 200 to the servers response POST to complete the normal HTTP request/response design for both the client and the server. This allows it to pass through HTTP proxy servers and direct support for them is included. Technically this is a loophole through most networks that only allow HTTP, because as you see we invented a new protocol that looks like HTTP, but in fact it is not.

XMLFoundation for Java

XMLFoundation supports Java too, it supports all Java data types like (string byte bool double long short) as well as Java data structures such as (Vector Stack ArrayList LinkedList TreeSet HashSet ). The XMLFoundation for Java is binary. If you want to build it yourself, you can because the source code to the entire JavaXMLFoundation is public and included in this release. There is no need to build it, but it's nice to be able to. I can hear some uneducated Java programmer already saying "I only want a 'Pure' Java solution". This is Pure. It's as pure as the JVM, because if you look close you'll see that it is actually an enhancement to the JVM.

The JVM (Java Virtual Machine) is written in C and C++. Your Java code runs anywhere the JVM can compile, and the XMLFoundation works the same way. The good news is that Java programmers don't have to deal with C++ just because their JVM is written in C++. The same is true of the XMLFoundation for Java.

The XMLFoundation uses JNI (Java Native Interface). It parses the XML in the native binary (that was created by a C++ compiler just like the JVM) and instantiates 'pure' Java Objects through JNI, then it assigns all the member variables just like the C++ XMLFoundation does. Can you think of a faster way to get the job done?

This is some sample code that uses the JavaXMLFoundation. A much more detailed example is included in the source code:

// Java source code that shows how to use the XMLFoundation using
// inheritance or containment. It is nearly identical to C++

import java.util.Iterator;
import java.util.Vector;


// MyLineItem has an "ObjectId", that is a value created from
// members and/or attributes of this object that uniquely identify
// it among all instances of it's own type. "ObjectId"'s are
// optional but allow you to perform complex "object updates"
// easily through XML. In main() below, this functionality is// used when getXML2() is applied. ObjectId's are like a database
// primary key in that they are generally not modified.
class MyLineItem extends XMLObject
{
     private String item;
     private String quantity;
     private int ItemID;
     MyLineItem()
     {
          // call the base class constructor with the XML-tag for 'this'
          super("LineItem");
     };    }
     MyLineItem(int nID, String itm, String qty)
     {
          super("LineItem");
          item = itm;
          quantity = qty;
          ItemID = nID;
     }

     void MapXMLTagsToMembers()
     {
          //         member      member         xml-tag           (optional)wrapper
          //-----------------------------------------------------------------
          MapMember(quantity,     "quantity",    "Quantity");
          MapMember(item,         "item",        "Description");
          MapMember(ItemID,       "ItemID",      "SKU");

          //////////////////////////////////////////////////////////////////
          // MapObjectId() is optional.
          //////////////////////////////////////////////////////////////////
          MapObjectId(this, "ItemID"); // takes 1 to 5 mapped 'Key parts'
     }
}


// Not "derived from" but "contains" XML support.
class Customer2
{
     public String          name;
     private int            CustID;
     private XMLObject      ContainedXMLObj;
     public MyOrder         objOrder;
     private Vector         vecStrings;

     long l;
     short s;
     double d;
     byte b;
     boolean z;


     public void XMLDump()
     {
          MyExchange("out");
          System.err.println( ContainedXMLObj.toXML() );
     }

     // indirect inheritance manages calls to FromXML() and ToXML()
     // manually, exposing them is optional. Member<-->XML exchange is
     // also done manually, generally following calls to FromXML() or ToXML()
     // this affords the developer full control for atypical implementations.
     void MyExchange(String inOut)
     {
          ContainedXMLObj.Member(this, inOut, b,     "b","byte","", 1);
          ContainedXMLObj.Member(this, inOut, z,     "z","bool","", 1);
          ContainedXMLObj.Member(this, inOut, l,     "l","long","", 1);
          ContainedXMLObj.Member(this, inOut, d,     "d","double","", 1);
          ContainedXMLObj.Member(this, inOut, s,     "s","short","", 1);
          sp;   "s","short","", 1);
          ContainedXMLObj.Member(this, inOut, name,     "name","FirstName","", 1);
          ContainedXMLObj.Member(this, inOut, CustID,     "CustID","CustomerID","", 1);
          ContainedXMLObj.Member(this, inOut, objOrder,     "objOrder",     "Order","MyOrder","");
          ContainedXMLObj.Member(this, inOut, vecStrings,"vecStrings",
              "StringItem","String",  "StringList Level2Wrapper");
     }

     public Customer2( String strXML )
     {
          // create a new 'empty' object that maps to "Customer".
          ContainedXMLObj = new XMLObject("Customer", false );
          ContainedXMLObj.fromXML(strXML);
          MyExchange("in");
     }
   
     // FromXML is not inheriterd, so we can expose the functionality through a
     // controlled accessor.
     public void ApplyXML( String strXML )
     {
          ContainedXMLObj.fromXML(strXML);
          MyExchange("in");
     }
}
// End of sample Java source code

This is some of the code I developed inside the JavaXMLFoundation that interacts with the JVM. (Don't worry you'll never have to work with this code.)

jobject MakeObjectInstance(JNIEnv *env,const char *pzObjectType,
                                 DynamicXMLObject *pDO,DynamicXMLObject *pDXOOOwner)
{
     if (env->ExceptionOccurred())
     {
          env->ExceptionClear();
     }

     jclass clazzA = env->FindClass(pzObjectType);
     jobject objReturnValue = 0;
     GString strType("Ljava/lang/String;");

     // if this class type exposes a 'ctor that takes a single XMLObject
     // we are using containment.
     jmethodID midctor = env->GetMethodID(clazzA, "", "(LXMLObject;)V");
     if (env->ExceptionOccurred())
     {
          env->ExceptionClear();
     }
     if (midctor)
     {
          // create a new java XMLObject instance
          jclass clazzX = env->FindClass("XMLObject");
          jmethodID midX =
                    env->GetMethodID(clazzX, "", "(Ljava/lang/String;)V");
          jstring     tagX = env->NewStringUTF(pDO->GetObjectTag());
          jobject objX = env->NewObject(clazzA, midX, tagX );

          // assign the object handle into the instance just created. bject handle into the instance just created.
          jclass clazz = env->GetObjectClass(objX);
          jfieldID fid = env->GetFieldID(clazz, "oH", "I");
          env->SetIntField(objX, fid, CastDXMLO(pDO));

          // create a new instance of some user defined java class that is
          // not extending XMLObject. Pass the XMLObject to the 'ctor.
          objReturnValue = env->NewObject(clazzA, midctor, objX );
     }
     else
     {
          // create an instance of a java object derived from the java XMLObject
          objReturnValue = env->AllocObject(clazzA);

          // assign the base class object handle directly.
          jclass clazz = env->GetObjectClass(objReturnValue);

          // any object that extends XMLObject will have the oH (Object Handle)
          // If the Object created is a String the fid will be 0.
          jfieldID fid = env->GetFieldID(clazz, "oH", "I");
          if (env->ExceptionOccurred())
          {
               env->ExceptionClear();
          }
          if (fid)
          {
               env->SetIntField(objReturnValue, fid, CastDXMLO(pDO));

               // create the jobject to DXO index
               union CAST_THIS_TYPE_SAFE_COMPILERS
               {
                    jobject   mbrObj;
                    void *    mbrVoid;
               }Member;

               Member.mbrObj = env->NewGlobalRef(objReturnValue);
               pDXOOOwner->addSubUserLanguageObject(Member.mbrVoid);
               // printf("===NewGlobRef[%d]\n",Member.mbrObj);
               pDO->setUserLanguageObject(Member.mbrVoid);
               cacheManager.addAlternate( pDO );
          }
          else if (strType.CompareNoCase(pzObjectType) != 0)
          {
            GString Err;
            Err.Format("Object type [%s] must either be derived from XMLObject\n"
            "or supply a constructor %s(XMLObject o)",pzObjectType,pzObjectType);
          }
     }
     pDO->SetObjectType(pzObjectType);
     return objReturnValue;
}

Java programmers will derive from this class - then the use is nearly identical to the C++ XMLFoundation:

import java.util.Vector;
import java.util.Stack;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.TreeSet;
import java.util.HashSet;

public class XMLObject {
     static { System.loadLibrary("JavaXMLFoundation");    }
     private static int InstanceId = 0;

     private native void JavaMap(int oH, int DataType,String strName,String xmlTag,
         String strWrapper, String ObjType, String strContainerType, int nSource);
     private native void JavaExchange(Object o, int oH, String inout,int nType,
         String b,String c,String d,String strObjectType, String strContainerType,
         int nSource);
     private native int  JavaConstruct(int n, String strXMLTag, int bAutoDataSync);
     private native void JavaDestruct(int oH);
     private native void JavaMapCacheDisable(int oH);
     private native void JavaMapOID(int oH, Object o, String Key1, String Key2,
         String Key3, String Key4, String Key5);
     private native XMLObject JavaGetSubObj(int oH);
     private native void JavaFromXML(int oH, String strXML);
     private native String JavaToXML(int oH);
     private native void JavaRemoveAll(int oH);

     private int          oH; // XML-Object Handle


     public void MemberRemoveAll()
     {
          JavaRemoveAll(oH);
     }

     protected void finalize()
     {
          JavaDestruct(oH);
     }
     protected void freedom()
     {
          JavaDestruct(oH);
     }

     public XMLObject(String strXMLTag)
     {
          oH = ++InstanceId;
          oH = JavaConstruct(oH, strXMLTag, 1);
     }
     public XMLObject(String strXMLTag, boolean bAutoDataSync)
     {
          oH = ++InstanceId;
          if (bAutoDataSync)
               oH = JavaConstruct(oH, strXMLTag, 1);
          else
               oH = JavaConstruct(oH, strXMLTag, 0);
     }

     // Override this 'virtual' method to map member to XML tags
     // through calls to MapMember();
     private void MapXMLTagsToMembers()
     {
     }
     void DontCacheMemberMaps()
     {
          JavaMapCacheDisable(oH);
     }
     void fromXML(String strXML)
     {
          JavaFromXML(oH, strXML);
     }
     String toXML()
     {
          return JavaToXML(oH);
     }


     private String MakeObjectName(String strIn)
     {
          if (strIn.compareToIgnoreCase("String") == 0)
          {
               strIn = "Ljava/lang/String;";
          };        }
          else
          {
               String sTemp = "L" + strIn + ";";
               strIn = sTemp;
          }
          return strIn;
     }


     //
     //    MapAttrib for each native data type (1st without the optional 'nested' argument)
     //  
     public void MapAttrib(long z, String pzName, String pzXMLTag)
     {
          JavaMap(oH,0,pzName,pzXMLTag,"","", "", 2);
     }
     public void MapAttrib(double z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,1,pzName,pzXMLTag,"","", "", 2);
     }
     public void MapAttrib(short z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,2,pzName,pzXMLTag,"","", "", 2);
     }
     public void MapAttrib(byte z, String pzName, String pzXMLTag)
     {
          JavaMap(oH,3,pzName,pzXMLTag,"","", "", 2);
     }
     public void MapAttrib(String z, String pzName, String pzXMLTag)
     {
          JavaMap(oH,4,pzName,pzXMLTag,"","", "", 2);
     }
     public void MapAttrib(int z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,5,pzName,pzXMLTag,"","", "", 2);
     }
     public void MapAttrib(boolean z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,6,pzName,pzXMLTag,"","", "", 2);
     }

     //
     //    MapAttrib for each native data type (now with the optional 'nested' argument)
     //  
     public void MapAttrib(long z, String pzName, String pzXMLTag, String pzNestedInTag)
     {
          JavaMap(oH,0,pzName,pzXMLTag,pzNestedInTag,"", "", 2);
     }
     public void MapAttrib(double z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,1,pzName,pzXMLTag,pzNestedInTag,"", "", 2);
     }
     public void MapAttrib(short z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,2,pzName,pzXMLTag,pzNestedInTag,"", "", 2);
     }
     public void MapAttrib(byte z, String pzName, String pzXMLTag, String pzNestedInTag)
     {
          JavaMap(oH,3,pzName,pzXMLTag,pzNestedInTag,"", "", 2);
     }
     public void MapAttrib(String z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,4,pzName,pzXMLTag,pzNestedInTag,"", "", 2);
     }
     public void MapAttrib(int z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,5,pzName,pzXMLTag,pzNestedInTag,"", "", 2);
     }
     public void MapAttrib(boolean z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,6,pzName,pzXMLTag,pzNestedInTag,"", "", 2);
     }

   
     //
     //    MapMember for each native data type (1st without optional nested-in-tag)
     //  
     public void MapMember(long z, String pzName, String pzXMLTag)
     {
          JavaMap(oH,0,pzName,pzXMLTag,"","", "", 1);
     }
     public void MapMember(double z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,1,pzName,pzXMLTag,"","", "", 1);
     }
     public void MapMember(short z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,2,pzName,pzXMLTag,"","", "", 1);
     }
     public void MapMember(byte z, String pzName, String pzXMLTag)
     {
          JavaMap(oH,3,pzName,pzXMLTag,"","", "", 1);
     }
     public void MapMember(String z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,4,pzName,pzXMLTag,"","", "", 1);
     }
     public void MapMember(int z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,5,pzName,pzXMLTag,"","", "", 1);
     }
     public void MapMember(boolean z, String pzName, String pzXMLTag )
     {
          JavaMap(oH,6,pzName,pzXMLTag,"","", "", 1);
     }
     public void MapMember(Object ob, String pzName, String pzXMLTag, String strObjectType )
     {
          JavaMap(oH,7,pzName,pzXMLTag,"",MakeObjectName(strObjectType), "", 1);
     }
     public void MapMember(Vector a, String pzName, String pzXMLTag, String strObjectType )
     {
          JavaMap(oH,8,pzName,pzXMLTag,"",MakeObjectName(strObjectType),"Ljava/util/Vector;", 1);
     }
     public void MapMember(Stack a, String pzName, String pzXMLTag, String strObjectType )
     {
          JavaMap(oH,8,pzName,pzXMLTag,"",MakeObjectName(strObjectType),"Ljava/util/Stack;", 1);
     }
     public void MapMember(ArrayList a, String pzName, String pzXMLTag, String strObjectType )
     {
          JavaMap(oH,8,pzName,pzXMLTag,"",MakeObjectName(strObjectType),"Ljava/util/ArrayList;", 1);
     }
     public void MapMember(LinkedList a, String pzName, String pzXMLTag, String strObjectType )
     {
          JavaMap(oH,8,pzName,pzXMLTag,"",MakeObjectName(strObjectType),"Ljava/util/LinkedList;", 1);
     }
     public void MapMember(TreeSet a, String pzName, String pzXMLTag, String strObjectType )
     {
          JavaMap(oH,8,pzName,pzXMLTag,"",MakeObjectName(strObjectType),"Ljava/util/TreeSet;", 1);
     }
     public void MapMember(HashSet a, String pzName, String pzXMLTag, String strObjectType )
     {
          JavaMap(oH,8,pzName,pzXMLTag,"",MakeObjectName(strObjectType),"Ljava/util/HashSet;", 1);
     }

     //
     //    MapMember for each native data type (now with optional nested-in-tag)
     //  
     public void MapMember(long z, String pzName, String pzXMLTag, String pzNestedInTag)
     {
          JavaMap(oH,0,pzName,pzXMLTag,pzNestedInTag,"", "", 1);
     }
     public void MapMember(double z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,1,pzName,pzXMLTag,pzNestedInTag,"", "", 1);
     }
     public void MapMember(short z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,2,pzName,pzXMLTag,pzNestedInTag,"", "", 1);
     }
     public void MapMember(byte z, String pzName, String pzXMLTag, String pzNestedInTag)
     {
          JavaMap(oH,3,pzName,pzXMLTag,pzNestedInTag,"", "", 1);
     }
     public void MapMember(String z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,4,pzName,pzXMLTag,pzNestedInTag,"", "", 1);
     }
     public void MapMember(int z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,5,pzName,pzXMLTag,pzNestedInTag,"", "", 1);
     }
     public void MapMember(boolean z, String pzName, String pzXMLTag, String pzNestedInTag )
     {
          JavaMap(oH,6,pzName,pzXMLTag,pzNestedInTag,"", "", 1);
     }
     public void MapMember(Object ob, String pzName, String pzXMLTag,
         String strObjectType, String pzNestedInTag )
     {
          JavaMap(oH,7,pzName,pzXMLTag,pzNestedInTag,MakeObjectName(strObjectType), "", 1);
     }
     public void MapMember(Vector a, String pzName, String pzXMLTag,
         String strObjectType, String pzNestedInTag )
     {
          JavaMap(oH,8,pzName,pzXMLTag,pzNestedInTag,MakeObjectName(strObjectType),
              "Ljava/util/Vector;", 1);
     }
     public void MapMember(Stack a, String pzName, String pzXMLTag,
          String strObjectType, String pzNestedInTag )
     {
          JavaMap(oH,8,pzName,pzXMLTag,pzNestedInTag,MakeObjectName(strObjectType),
              "Ljava/util/Stack;", 1);
     }
     public void MapMember(ArrayList a, String pzName, String pzXMLTag,
          String strObjectType, String pzNestedInTag )
     {
          JavaMap(oH,8,pzName,pzXMLTag,pzNestedInTag,MakeObjectName(strObjectType),
              "Ljava/util/ArrayList;", 1);
     }
     public void MapMember(LinkedList a, String pzName, String pzXMLTag,
          String strObjectType, String pzNestedInTag )
     {
          JavaMap(oH,8,pzName,pzXMLTag,pzNestedInTag,MakeObjectName(strObjectType),
              "Ljava/util/LinkedList;", 1);
     }
     public void MapMember(TreeSet a, String pzName, String pzXMLTag,
          String strObjectType, String pzNestedInTag )
     {
          JavaMap(oH,8,pzName,pzXMLTag,pzNestedInTag,MakeObjectName(strObjectType),
              "Ljava/util/TreeSet;", 1);
     }
     public void MapMember(HashSet a, String pzName, String pzXMLTag,
          String strObjectType, String pzNestedInTag )
     {
          JavaMap(oH,8,pzName,pzXMLTag,pzNestedInTag,MakeObjectName(strObjectType),
              "Ljava/util/HashSet;", 1);
     }

     //
     //    Map ObjectID's - the JavaXMLFoundation works just the same with respect
     // to object caching
     //  
    public void MapObjectId(Object o, String Key1)
     {
          JavaMapOID(oH, o, Key1, "", "", "", "");
     }
     public void MapObjectId(Object o, String Key1, String Key2)
     {
          JavaMapOID(oH, o, Key1, Key2, "", "", "");
     }
     public void MapObjectId(Object o, String Key1, String Key2, String Key3)
     {
          JavaMapOID(oH, o, Key1, Key2, Key3, "", "");
     }
     public void MapObjectId(Object o, String Key1, String Key2, String Key3, String Key4)
     {
          JavaMapOID(oH, o, Key1, Key2, Key3, Key4, "");
     }
     public void MapObjectId(Object o, String Key1, String Key2, String Key3,
          String Key4, String Key5)
     {
          JavaMapOID(oH, o, Key1, Key2, Key3, Key4, Key5);
     }


     //
     //    Get/Set Member for each native data type
     //  
     public void Member(Object o, String xfer, long z, String pzName, String pzXMLTag,
          String pzNestedInTag, int nSource )
     {
          JavaExchange(o,oH,xfer,0,pzName,pzXMLTag,pzNestedInTag,"","", nSource);
     }
     public void Member(Object o, String xfer, double z, String pzName, String pzXMLTag,
         String pzNestedInTag, int nSource )
     {
          JavaExchange(o,oH,xfer,1,pzName,pzXMLTag,pzNestedInTag,"","",nSource);
     }
     public void Member(Object o, String xfer, short z, String pzName, String pzXMLTag,
          String pzNestedInTag, int nSource)
     {
          JavaExchange(o,oH,xfer,2,pzName,pzXMLTag,pzNestedInTag,"","",nSource);
     }
     public void Member(Object o, String xfer, byte z, String pzName, String pzXMLTag,
          String pzNestedInTag, int nSource )
     {
          JavaExchange(o,oH,xfer,3,pzName,pzXMLTag,pzNestedInTag,"","",nSource);
     }
     public void Member(Object o, String xfer, String z, String pzName, String pzXMLTag,
          String pzNestedInTag , int nSource)
     {
          JavaExchange(o,oH,xfer,4,pzName,pzXMLTag,pzNestedInTag,"","",nSource);
     }
     public void Member(Object o, String xfer, int z, String pzName, String pzXMLTag,
          String pzNestedInTag, int nSource )
     {
          JavaExchange(o,oH,xfer,5,pzName,pzXMLTag,pzNestedInTag,"","",nSource);
     }
     public void Member(Object o, String xfer, boolean z, String pzName,
          String pzXMLTag, String pzNestedInTag, int nSource )
     {
          JavaExchange(o,oH,xfer,6,pzName,pzXMLTag,pzNestedInTag,"","",nSource);
     }
     public void Member(Object o, String xfer, Object o2, String pzName,
          String pzXMLTag, String pzObjectType, String pzNestedInTag )
     {
          JavaExchange(o,oH,xfer,7,pzName,pzXMLTag,pzNestedInTag,
              MakeObjectName(pzObjectType),"",1);
     }
     public void Member(Object o, String xfer, Vector a, String pzName,
          String pzXMLTag, String strObjectType, String pzNestedInTag )
     {
          JavaExchange(o,oH,xfer,8,pzName,pzXMLTag,pzNestedInTag,
              MakeObjectName(strObjectType),"Ljava/util/Vector;",1);
     }
     public void Member(Object o, String xfer, Stack a, String pzName,
          String pzXMLTag, String strObjectType, String pzNestedInTag)
     {
          JavaExchange(o,oH,xfer,8,pzName,pzXMLTag,pzNestedInTag,
              MakeObjectName(strObjectType),"Ljava/util/Stack;",1);
     }
     public void Member(Object o, String xfer, ArrayList a, String pzName,
          String pzXMLTag, String strObjectType, String pzNestedInTag )
     {
          JavaExchange(o,oH,xfer,8,pzName,pzXMLTag,pzNestedInTag,
              MakeObjectName(strObjectType),"Ljava/util/ArrayList;",1);
     }
     public void Member(Object o, String xfer, LinkedList a,
          String pzName, String pzXMLTag, String strObjectType,
          String pzNestedInTag )
     {
          JavaExchange(o,oH,xfer,8,pzName,pzXMLTag,pzNestedInTag,
              MakeObjectName(strObjectType),"Ljava/util/LinkedList;",1);
     }
     public void Member(Object o, String xfer, TreeSet a, String pzName,
          String pzXMLTag, String strObjectType, String pzNestedInTag )
     {
          JavaExchange(o,oH,xfer,8,pzName,pzXMLTag,pzNestedInTag,
              MakeObjectName(strObjectType),"Ljava/util/TreeSet;",1);
     }
     public void Member(Object o, String xfer, HashSet a,
          String pzName, String pzXMLTag, String strObjectType, String pzNestedInTag )
     {
          JavaExchange(o,oH,xfer,8,pzName,pzXMLTag,pzNestedInTag,
              MakeObjectName(strObjectType),"Ljava/util/HashSet;",1);
     }
}

About the author(s) of XMLFoundation

The XMLFoundation was designed and developed mostly by myself, however I had help from co-designers on the NCIS (National Clinical Information System) Project, and mostly only 1 other co-developer. Special thanks to the SAIC management who believed in me and gave me the opportunity to develop the mother product. Thanks to everyone who stood beside me during the long and expensive labor of putting this work together. "I told you so" to everyone else. In the end technology prevails over politics and ignorance. The XMLFoundation contains several independent algorithms that were developed by other authors - and their supporting communities - their source code contains more information about them. Historically it has been the solo engineers that set the direction for the masses. Bjarne Stroustrup incremented the work of Brian Kernighan and Dennis Ritchie. There are countless contributors from the purest perspective of technology advancement and they could not possibly all be named here.

Conclusion

In conclusion, this started a long time ago and it's not going away anytime soon. It's a masterpiece conspiracy to end times of high crimes.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Brian Aberle
United Business Technologies
United States United States
Member
https://skydrive.live.com/?cid=d7ec275e76d295cf

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: MapObjectID does not work for mapped attributes and couple of other issuesmembermKlus11 Feb '13 - 11:10 
Yesterday, I was doing some performance and robustness testing on the XmlFoundation library to see if it would be good match for our project. I generated an xml that has 1000 owners and each has 20 cars. Second, the 'update' xml has 100 owners and each owner has 20 cars.
 
I noticed two, not good, things Frown | :(
 
1. When I load both xml into the CCarLibrary object it consumes nearly 1GB of memory. Note that the original xml size is 23MB and the update xml size is 244KB.
 
2. When the CCarLibrary object is being deleted (i.e. when application exists) it causes an exception in the ObjectCache clean method.
 
I have uploaded the sample xml files to https://www.dropbox.com/s/zef2hc15d24w9kp/XmlFoundation_test.7z[^]
GeneralRe: MapObjectID does not work for mapped attributes and couple of other issues [modified]memberBrian Aberle11 Feb '13 - 12:07 
I know whats causing the memory usage. GStrings allocate 256 bytes and you have many ~10 byte strings that are being stored in them. You might consider mapping to a char buffer[] to reduce memory usage. You might also consider setting your own GString buffer size to about 15 which will hold every element and attribute tag name in your application without ever making calling new() to expand the small default buffer size that fits your application better.
 
The performance times look good, even using the slower late bound OID.
 
The process exit runs very slow under the debugger because of the debuggers memory management. So slow that I gave up and built it in release to see the exception.
 
----------------------- Post Modified: -------------------------
 
OK - I don't have the final fix for this exception yet. But....
 
if you comment out the first 5 lines in the XMLObjectCache ~dtor like this:
 
XMLObjectCache::~XMLObjectCache()
{
//	dumpCache();
//	dumpStateCache();
//	dumpForeignCache();
//	delete m_cache;
//	delete m_cacheState;
//	delete m_cacheForeign;

 
That prevents the exception. Note that the ObjectCache is global and this ~dtor is ONLY called at application exit so this workaround does not cause a memory leak.

modified 11 Feb '13 - 18:54.

GeneralRe: MapObjectID does not work for mapped attributes and couple of other issuesmemberBrian Aberle11 Feb '13 - 15:28 
Go get the latest code. I massively reduced the memory used by this example. After you get the code, modify
#define DEFAULT_INITIAL_SIZE    10
in GString.h
 
Change the value in the mainline build from 256 to 10 which is large enough to hold your element and attribute tag names as well as the values you bind to. If one was to exceed your small default, GString will automatically expand to the need. That expansion is slow so it should be avoided.
 
Also - look at the code i put in ~XMLObjectCache().
 
I like your example program, and the huge data files compress down so small that I think it should be added as an example program in the source distribution.
GeneralRe: MapObjectID does not work for mapped attributes and couple of other issuesmembermKlus18 Feb '13 - 10:43 
Hi Brian,
 
Thanks for this.
I tried setting the initial size for GString to 10 and that reduced the mem footprint to 50%. I also tried changing to STL (GString to std::string and GList to std::list) and that reduced the mem footprint by another 50%. So I went from 1GB to 500MB to 250MB which could be acceptable.
 
For the crash in XMLObjectCache detor the try..catch didn't solve it. I'm using the previous suggested workaround - I commented out the delete and clear methods.
 
Now, I have another challenging problem to solve. The below example is to only demonstrate my problem. It's not the best match for what I'm actually doing but that should do it...
 
Let's say that I have 6 base xml files that have list of cars that are available for sale. 1 xml file for cars available in New South Wales, 1 for Victoria, 1 for Queensland, 1 for South Australia, 1 for Western Australia and 1 for Northern Territory. Now every dealer in each state has some additional info for some cars that he keeps in separate xml file (same schema). Let's say every state has 10 dealers. So we have additional 60 'derived' xml files that only have the additional info.
Now I need to load the data in ALL xml files into runtime (XmlCache.exe?). Other processes make RPC calls into the XmlCache.exe to request data for particular car.
 

The solution that would utilize the XML Foundation could be like this:
Load first base xml (cars available in New South Wales) into CCarLibrary object, make 9 additional copies of CCarLibrary. Load 10 derived xml files (from 10 dealers in New South Wales) into those 10 CCarLibrary objects. Now will do the same for the another 5 base and 50 derived xml files. We will end up with 60 CCarLibrary objects.
This solutions has couple of issues. There is no copy constructor or copy operator for XmlObject. The memory footprint of the XmlCache.exe will be large.
 
Do you have any suggestions on that? Smile | :)
 
Thanks,
Marek
GeneralRe: MapObjectID does not work for mapped attributes and couple of other issuesmemberBrian Aberle18 Feb '13 - 14:15 
Real quick, I can say notice this:
int XMLObject::CopyState(XMLObject *pCopyFrom)
 
Im glad you have the memory use down. I have adjusted that GString buffer size for myself before so I like that it is easier now. I think the default should probably be 64, rather than 256, and on average that might serve most folks better. The tradeoff is a performance penalty for tag names or values larger than the default.
 
I can not say that I immediately understand this situation you are explaining above. Example programs are easier for me to work with. I had to comment out some of the STL iterator code in the example you posted because it didnt compile for me. In the STL example in the XMLFoundation source distribution there are two code branches for Microsoft compilers and neither of them works in Linux. It's not very standard.
GeneralRe: MapObjectID does not work for mapped attributes and couple of other issues [modified]membermKlus18 Feb '13 - 15:20 
OK, let's try the below example. It's hopefully more descriptive than what I was trying to say before Smile | :)
 
// load the base xml
CCarLibrary *pBaseLib = new CCarLibrary();
pBaseLib->FromXML(GetFileContents("Base.xml"));
 
CCarLibrary *pDerived1 = new CCarLibrary(pBaseLib); // clone the base library
pDerived1->FromXML(GetFileContents("Update1.xml")); // update the base with update 1 (do not include update 2 nor update 3)

CCarLibrary *pDerived2 = new CCarLibrary(pBaseLib); // clone the base library
pDerived2->FromXML(GetFileContents("Update2.xml")); // update the base with update 2 (do not include update 1 nor update 3)

CCarLibrary *pDerived3 = new CCarLibrary(pBaseLib); // clone the base library
pDerived3->FromXML(GetFileContents("Update3.xml")); // update the base with update 3 (do not include update 1 nor update 2)

// Query xml caches
GString *pResultXml = new GString();
XMLObject *pFound = NULL;
 
// find object I'm interested in in derived 1 library only (using XPath)
pFound = pDerived1->Find("/Owners/Owner[Name=John]");
pFound->ToXML(pResultXml);
 
// find object I'm interested in in derived 2 library only (using XPath)
pFound = pDerived2->Find("/Owners/Owner[Name=John]");
pFound->ToXML(pResultXml);
 
// find object I'm interested in in derived 3 library only (using XPath)
pFound = pDerived3->Find("/Owners/Owner[Name=John]");
pFound->ToXML(pResultXml);
 
One issue is that there is no copy contructor for XMLObject, and second is that there is no Find function that would take an XPath and return XmlObject.
 
You suggested to use
XMLObject::CopyState(XMLObject *pCopyFrom)
but that doesn't work for me.
 
To achieve what I want I'd have to load the base xml multiple times:
    CCarLibrary *pDerived1 = new CCarLibrary();
    pDerived1->FromXML(GetFileContents("Owners.xml")); // load base xml
    pDerived1->FromXML(GetFileContents("Owners_update1.xml")); // update the base with update 1 (do not include update 2 nor update 3)

    CCarLibrary *pDerived2 = new CCarLibrary();
    pDerived2->FromXML(GetFileContents("Owners.xml")); // load base xml
    pDerived2->FromXML(GetFileContents("Owners_update2.xml")); // update the base with update 2 (do not include update 1 nor update 3)

    CCarLibrary *pDerived3 = new CCarLibrary();
    pDerived3->FromXML(GetFileContents("Owners.xml")); // load base xml
    pDerived3->FromXML(GetFileContents("Owners_update3.xml")); // update the base with update 3 (do not include update 1 nor update 2)
 
But that isn't the most efficient way ... :(

modified 18 Feb '13 - 22:01.

GeneralRe: MapObjectID does not work for mapped attributes and couple of other issuesmemberBrian Aberle27 Feb '13 - 7:01 
I don't know why you want multiple copies of the objects. I suspect that there is a better way to accomplish what you are doing. Typically you can resolve the XPath access data using direct c++ data access in the form of Object.Member.
 
For a small consulting fee, I could analyze your situation and apply the best implementation. Currently I can be reached at RoaringCheckmate@live.com.
 
I work hard, and play hard. I have been out playing( http://sdrv.ms/YXQnOP[^] ), now I'm looking for some work.
GeneralRe: MapObjectID does not work for mapped attributes and couple of other issuesmembermKlus3 Mar '13 - 17:22 
I understand that it's hard to understand what I'm trying to achieve here without more specific examples and scenarios.
 
Anyway, I've decided to use the pugixml library instead as it will better match my needs.
 
But I appreciate you help and inputs!
GeneralRe: MapObjectID does not work for mapped attributes and couple of other issuesmemberBrian Aberle4 Mar '13 - 6:19 
If it's not too much trouble put together a comparison application that shows how the other tools help you manage multiple copies of the base XML with caching enabled. Obviously if you undefined the OID, which by definition must be unique, then you can keep 10 copies of the base XML in your app. How are you handling your indexed updates?
GeneralMessage from the authormemberBrian Aberle27 Nov '12 - 2:49 
I have been in prison for the last 2 years. The authorities confiscated my last latop and will not return it. Moral of the story: Encryption.
 
One kind individual donated a dual core laptop with a 320gb disk, 64 bit Windows 7, and VS2012 Pro. The kind individual is the antithesis of police who stole the last one.
 
I had a system of distributed backups that has allowed me to restore every line of source code I’ve written since a long time ago. I will port XMLFoundation to 64 bit now. If you have any comments/questions/suggestions bring them to me now and they will be addressed in this next release.
 
After an exhaustive legal battle to defend the truth I need money. If anyone can hire me as a consultant or donate or invest in me please send me an email: RoaringCheckmate@.live.com
People who know the truth have a responsibility and the Internet provides a highway for truth that the authorities cannot control. Today the courts in Georgia(usa) are having a hearing to decide if I deserve a new new trial. I will not attend because the hearing is in Bartow County where I am not safe and justice is perverted.
 
On June 14, 2012 I sent an email from inside prison via contraband phone to several people who showed concern by making phone calls to the authorities about the deadly and inhumane imprisonment conditions where I was serving time for “Escape”. My lawyer, Marcia Shein from Decatur, called warden Stanley Williams when the legal mail she sent was not being delivered to me. Paper mail is regulated in prison, even legal mail can get lost. E-mail is not regulated - so e-mail enables a power that was intended to be forbidden by the prison administration. By using this forbidden power, I contacted individuals which ultimately manifested my release from prison on October 5, 2012.

The full text of my USC 1983 lawsuit describes how I was held naked in a cold cell for weeks, put on disciplinary diets for months, held in a 2 man cell with 4 men in it while 2 of them had active staph infections, had my mail tampered with, had housing intending harm including 60 days in the booking intake area, and denied legal necessities by the same sheriff who stole my laptop computer. The Federal court in the Northern District of Georgia has failed to respond to these violations of the US Constitution in a timely manner, so the situation is being presented to the United Nations Office of Human Rights that upholds the “Universal Declaration of Human Rights” which has also been violated. The matter should be brought to international courts if federal authorities will not condemn the illegal actions of state authorities. It is appropriate for the UN to take jurisdiction according to the founding charter of the United Nations.
 
The email I sent from prison on June 14 rightly accused the State of Georgia of trying to kill me. That e-mail caused the Georgia Department of Corrections to send an Internal Affairs investigator to meet with me the following day. Prison administration, angry for the stir I caused with forbidden internet access, punished me with various acts including a month in isolation (the hole), 5 property shakedowns and strip searches in a 5 week period, and being locked in a 1 man shower stall multiple times once for 5 hours. During the time I was in the hole the violence in the dorm I came out of escalated with over 10 new stabbings in just a few weeks. On July 19, 2012 one prisoner died in that dorm. At the time I sent the e-mail there had been 18 people stabbed in that 100 man dorm during the 9 months I had been there. About 30% of the prisoners in that dorm were stabbed in a 10 month period. National Geographic recently called Smith State the worst prison in Georgia and one of the worst in the US. The Georgia Dept. of Corrections put me in the most violent dorm in that prison. My assessment of the danger being life threatening is accurate based on the facts. Georgia authorities use indirect capital punishment by creating the form of imprisonment and classification that they do.

This was actually more of an escape from Smith State Prison (Level 5 Disciplinary Camp) than a release due to people calling the prison and other authorities after learning of my situation via my contraband internet access. I was unexpectedly released on parole to no address. I am as free as a homeless man on house arrest. The federal court in the Northern District of Georgia recently ruled that my indigent financial state allows me to proceed in court without paying fees, therefore parole fees will also be an unreasonable demand.
 
In 2008 the 9th circuit in the Northern District of California ruled in my case when I violated federal probation for not reporting or paying fees: The Honorable judge Martin Jenkins ruled that I was Not Guilty because "the United States does not have a debtor’s prison". He then ordered the US Marshalls to reimburse my meals, hotel, and travel costs while I attended the probation revocation hearing in San Francisco. The Honorable Judge Martin Jenkins made that constitutional ruling that set me free while the US Attorney petitioned for prison time. Judge Jenkins has since moved from the 9th circuit to the U.S. Court of appeals. I am free from fines fees and obligation. Unjust probation justifies escape. Bartow County owes me lunch. The State of Georgia owes me freedom. They are in debt with me.

I was on unjust misdemeanor probation in Bartow County. The details of that “Reckless Conduct” charge in 2009 that turned into probation for climbing to the top of a water tower is documented in part 13 of my 2009 journal that contains photos of the climb and the documents of the double booking and double bonding episode that kept me initially imprisoned for 21 days for climbing the ladder. I had already been illegally over punished. I never reported to probation, and was arrested one year later for no reason other than that. The "Bartow Blotter" recorded that arrest on October 15, 2010 stating [* Brian Troy Aberle, 38, of 1101 N. Tennessee St., Cartersville, was arrested by Cartersville police and charged with probation violation.] The sheriff’s son, David Millsap, was a frequent guest at that address where I was conducting my personal investigation into the truth. I was sentenced by the probation officer to my choice of 9 weeks in jail or to pay a $2500 fine in addition to all that they had cost me already. I also knew about corruption in the Sheriffs Department. I chose to escape.
http://www.daily-tribune.com/view/full_story/10141300/article-Inmate-escapes-from-BCSO-work-detail?instance=crime_log
This was my first escape.
 
The arrest required coordination between US Marshalls, Cobb County Sheriffs, Bartow County Sheriffs and City of Smyrna police all of which were present for the arrest. The warrant did not grant authority to take my property. However, Bartow County deputy Gavon Wilkins took my laptop during the arrest. Why did they want the laptop so bad that they broke the law to take it? He was outside his jurisdiction and without a warrant to seize property. The sheriffs should be held to law and prosecuted for Theft by Taking, of my personal property. Bartow County demands money from me while they are in debt with me and therefore deserve even greater condemnation. They charged me with Theft by Taking for the clothes I took during my escape therefore they will be judged for what they did actually steal. http://www.daily-tribune.com/view/full_story/10194038/article-Work-detail-escapee-caught
The theft was the least of the crimes that I experienced in Bartow County. I filed a lawsuit about the cruel, unusual and unconstitutional conditions that I endured under the Bartow County Sheriffs. http://dockets.justia.com/docket/georgia/gandce/4:2011cv00301/179936
 
The Federal court in the Northern District of Georgia has taken over a year and still not made a ruling in this civil rights lawsuit titled "Brian Aberle vs. Clark Millsap". The federal court has neither administered justice nor responded in a timely manner considering the serious and extreme violations documented in this lawsuit. The content of this lawsuit quickly came under FBI investigation. FBI agent Stanley Slater came to interview me at Smith State Prison on February 01, 2012 regarding this lawsuit. The full text of the lawsuit is published here: https://skydrive.live.com/?cid=d7ec275e76d295cf&id=D7EC275E76D295CF%21797
 

Back in 2007, the federal court in the Northern District of California had put me on probation because the over-zealous US Attorney was able to write a confession regarding my 1999 tax return inaccurately and threaten my wife and co-defendant with state custody of my children to leverage my wife of 13 years and mother of my 7 children to sign the confession as they worded it. She was told she would serve prison time if she did not sign it. My confession was written by the same US Attorney and came with the promise of release from incarceration if I agreed to his version of the confession. At my first hearing to enter the plea, after the judge had finished reading the confession he asked if the confession was correct, and I answered "That’s not exactly how I would explain it". The honorable judge terminated the hearing because of my answer but rescheduled the hearing for the following day when I was instructed that I must say "yes" to be released. http://www.justice.gov/tax/usaopress/2007/txdv072007_04_13_aberle_sentencing_press.pdf
 
I am actually innocent of "Tax Evasion". I pay tax that I owe and never misstated anything on my personal and corporate returns that were filed by a CPA. I explained the details in a chapter I wrote in a 2006 book titled "If I die this is why they did it." That book about illegal tyrannical IRS policies also included a chapter about the failure of the war on drugs, a topic that led me to Bartow County. I am also actually Not Guilty of Escape, because the incarceration was not constitutionally lawful therefore the escape was. To be certain the sheriff knows I am unapologetic, I escaped a second time. The second escape took place out of the "Maximum Security" dorm where I climbed the recreation yard wall to the roof above visitor parking, beyond all the fences.
http://cartersville.patch.com/articles/jail-inmate-attempts-escape

http://www.calhountimes.com/view/full_story/11500592/article-Bartow-Co--inmate-captured-on-jailhouse-roof-after-attempted-escape
 
Sheriff Clark Millsap knows me as a journalist or investigator researching about the whole story behind the convictions of a senior GBI agent who maintained a desk at the Bartow County Sheriffs department, and a former captain and head of the Drug Task Force for Bartow Sheriffs Department. They were convicted for pocketing cash and reselling guns illegally confiscated from drug dealers. I had emailed Sheriff Clark Millsap long before the escapes regarding my work.
http://www.justice.gov/usao/gan/press/2006/07-27-06.pdf
 
http://rn-t.com/view/full_story/3478462/article-Former-Bartow-officer-gets-13-month-sentenc---Breaking-New
Nobody was ever prosecuted for all the drugs stolen from the Sheriffs evidence locker and from drug dealers. Those drugs were sold back onto the street in Chattanooga. When the drugs were stolen from the evidence locker it caused the district attorney to become aware that evidence required for trial was not available. The District Attorney chose to focus his energy on getting a plea confession signed at any cost. The cases that demanded a jury trial were eventually dismissed for statute of limitations expiration. The DA, Sheriff, and Judge help to conceal the true extent of the crimes that actually took place in their county. All the convictions by plea are void due to the unscrupulous motivation to deny a trial that is a constitutional right.
 
The failure of justice is in plain sight for all who are willing to look at it. I escaped two times from a sheriff that had drugs stolen from his evidence locker. The sheriff and judge together chose to cover up the theft and punish the escape. The FBI also chose to under-punish the sheriff’s captain who was only charged for pocketing cash and reselling guns that were illegally confiscated from drug dealers. The actual amounts were no less than $800,000 but only a small fraction of that was on the indictment. The juries agreed that my case was over charged and found me Not Guilty of the additional indictment charges that were also "Terroristic Threats" that I allegedly made to Sheriff Clark Millsap, "Dissemination of Terroristic Threats", "Interference with Government Property" and "Theft by Taking". All I did was "Escape", I never threatened him with anything but truth. Those who by mercy had been undercharged were overcharging me so they deserve the greater condemnation.
 
The justice system is perverted. When the sheriffs son, David Millsap, was first caught with drugs and a gun he was not booked at the jail until 19 hours later after deciding that it could not be ignored due to the witnesses. This gave him time to go home, call dad, and get his bond money ready so that he could bond out before ever being held in custody at the jail. It would be nice if average people got such good treatment from the sheriff when they get arrested with dope and guns. David Millsap’s indictment didn’t come until 4 years later. My over charged indictment came immediately; his was almost lost for good. The District Attorney says that there is no foul play in the justice system but those with eyes to see must willfully believe that lie or reject that lie. http://www.daily-tribune.com/view/full_story/19839526/article-Grand-jury-indicts-sheriff-s-son-in-2008-case?instance=homefirstleft
 
My lawyer, Marcia Shein, has been ineffective against such collectively powerful people that work together to manipulate justice. She recently told me that she would need more money if I want to have private investigators document imprisonment conditions that justify escape and cause my trials to have been unfair without access to mail, phones, visitation, or even pen and paper while in the custody of Sheriff Clark Millsap. She has exhausted my finance resources and Bartow County has already paid for two jury trials. I deserve another jury trial since I had no lawyer and represented myself Pro Se at both trials when the violations of my rights denied me a fair trial. I need a Change of Venue which judge Carey Nelson already denied. The judge was aware of the barbaric conditions of my imprisonment and my research and he allowed the trial to take place. He is Party to a Crime of convicting me to further his Party to Crime in the cover up of the drugs stolen from the evidence locker. I am scheduled to have un-honorable judge Carey Nelson rule on a motion for new trial on November 27, 2012 in the Superior Court of Bartow County.
 
I have additional documentation that explains more. Everything can be found from here:
https://skydrive.live.com/?cid=d7ec275e76d295cf
 
At the above link you will see a list of folders. In the "Book" folder you will find the manuscript of "If I die this is why they did it", and the journal files that must be unzipped to your machine to be properly viewed with the images and audio that are important portions of this documentation. In the folder labeled "Business" is a technology prospectus of my software development company, United Business Technologies. In the “Other” folder is music and video I publish.
 
I attached my resume of my professional background, summarized it is this: Expert integration (B2B) technology. I served as Architect and engineering team lead (of the team with the most critical path dependencies) building a $2B NCIS National Clinical Info System. I presented project designs to the Kaiser CTO(Paul Fingeman at the time) on behalf of SAIC who won the contract. SAIC is the largest private engineering firm in the U.S. and they consulted me for leadership positions. I am internationally recognized as an expert in software architecture. I publish an open source public project at codeproject.com as ‘XMLFoundation.’
 
--Forwarded Message Attachment--
Resume of Brian Aberle

Life Skills:
• Listening carefully is my greatest skill, discerning what to listen to is my gift
• Leading by example and earning the respect of the minority who provide the majority of work effort
• Explaining complicated things in simple terms and only contributing beneficial input
• Identifying theory amid facts, finding failure points, and second guessing assumptions
________________________________________
Technical Skills:
• Extensive use of C++ Framework Design/Development - Java/VB/.NET environments
• Expert XML/B2B built XML parsers, bridge DCOM-CORBA w/ XML, Distributed XML Objects
• Security: OpenSSL, SSLeay, RSA, RSA Bsafe, X.509's, Cert Authorities, Design patterns, 2Fish
• Performance Patterns: Advanced threading, pooling, caching, recycling, memory management
• DBMS usage: SQL engines, DB-LIB, OCI, 4GL SQL generators, TP monitors, SQL parsers
• Servers (Internet Commerce, Security, Data Warehouse) - HTTP/ISAPI/CGI/XML interfaces
• Project planning and design - Foundation and Architecture design for large team implementations
• Enterprise Distributed Application Architecture and Development (CORBA, DCOM, RPC)
• Smart card E-Commerce technology - iButton, Spyrus, VISA open platform
• Develop on: Intel/Alpha NT, RS6000 AIX, Solaris, VAX , IBM 36/38&AS/400, x86 Linux,ARM(CE)
• Application Server Technologies Design (Transactional Integrity, MTS, Encina, Tuxedo, MSMQ)
• Tunneling, Routing, and Bridging of TCP connections and protocols across several platforms
________________________________________
Industries:
Banking, Cellular, Credit Cards, Data Warehousing, Internet Commerce, Insurance, Medical, and Scientific
________________________________________
Education:
Advanced OLE class- (Univ. CA Berkley extension) Hayward, California 1995
Client/Server Technologies - (AMS) Hoevelacken, Holland 1994
Object Oriented Analysis and Design Theory - (DBMI) Lisbon, Portugal 1994
IBM Mission Critical System Recovery Training - (IBM) Atlanta, Georgia 1992
Metropolitan State College of Denver (1 year) Denver, Colorado 1992

________________________________________

United Business Technologies (B2B Technology Vendor Initiative) Founder and Owner
2000 to Present
Most recently my focus has been in development of systems integrations components. I architected and managed development of TransactXML server, a transactional XML layer over most databases on most platforms, that supports joining foreign databases to render a single XML document. XMLJournal magazine called it “World Class”. I architected XMLFoundation. I also contributed to DesignerXSL, an XSL design tool debugger and XSLT transformer. I designed and developed Xfer, an engine for connecting across sub-networks and unlike platforms securely. Xfer allows secure connection routes to be established through various firewalls by tunneling through HTTP and “reverse connecting” through NAT routers using polling, this works well in conjunction with the previous products mentioned. I also designed and developed PackMan(Package Manager), a portable file system useful to deliver business documents such as invoices that accompany digital data such as sound, images, CAD files or designs.

SAIC for Kaiser Permanente (NCIS Project) Consulting Team Lead
Oakland, California Nov 1997 - Jan 1999
• Served as Core Team Lead for NCIS (National Clinical Information System) to serve 60,000 MD’s
• Lead the development team with the most critical path dependencies on largest project in the world
I served as Architect, Team Lead, and Programmer building the largest health care information system in the world. I discovered a DCOM scalability enhancement in 1997 that allows the server to connect many clients through a single instance of a stateless server-side interface. I produced better scalability than could be achieved through a well-implemented Transaction Server Interceptor and presented the proposed architecture to the vice president for technology planning at Kaiser Permanente on behalf of SAIC.
I developed object serialization in XML format. COM & CORBA objects serialize to and from an XML stream to transfer proxy cache state. My team built an XML 1.0 parser with DTD validation. XML parsed directly into destination business objects without building memory trees or using DOM.
Database requests and responses pass through XML representation to construct distributed objects. Many teams were dependent on our stable and timely deliverables in the 600 man NCIS (National Clinical Information System Project) Phase 1.
My team fully researched every aspect of building the best possible DCOM and CORBA servers. The CORBA Server implements complete custom memory management and distributed reference-counting designs. We built Smart Proxies and tested many different scenarios with respect to TP monitors, Threading, Object Recycling, and Thread Pooling. I was responsible for building the Object-XML development framework and XML parsers used by almost every development team, and business affiliate (Ontyx, Oceania, Pegasystems) for the NCIS project during phase 1.
 
Neopost (E-Postage Project for US Postal System) Consultant
Hayward, California Jan 1999 - Mar 2000
• Served as software developer with full authority of implementation design and methods
Developed complete back end processing system, end user software, and customer service representative tool as an XML client that made all database updates through XML using UBT’s TransactXML Server. XML Query responses were transformed through our custom built XSL engine into HTML for viewing and ACH for payments. The system consisted of a moderately complex transactional model with hundreds of stored procedures and database integrity rules that were impossible to validate through standard DTD.
The end user product was a Smart Card based system that stored digital cash to print postage and render 2D postal barcodes with USPS sender tracking data, built as a browser based application. Use of digital signatures was certified for validation using NIST FIPS guidelines.
The use of XML to represent all database updates was bleeding edge in 1999. Unlike other pioneering efforts of the time, our solution did not consist of special server side processing logic for each transaction.
 
Siemens Medical Systems (Primeview project) Consultant
Concord, California 1997 and 1998
• Developed software to meet an internally prepared detailed design specification
I developed a Radiation Delivery information system for Siemens Medical. The software was in the strictest FDA classification -- Death may result from system error -- as it controlled motor movement and radiation intensity and duration - (like Therac 25 did). The software allowed for an industry first, delivering precise radiation doses through a Liner Accelerator in an auto-sequenced delivery. Virtual electron beam intensity shaping was implemented in software by shifting patient position and accelerator position during an electron treatment. The ‘virtual beam’ was modeled in the software GUI by calculating a cumulative dosage intensity graph within the treatment area accounting for both the motorized movement of the patient and the accelerator. The "auto-sequenced" delivery software safely scripts all steps of a prescription delivery so that human operator error is reduced and treatment time is reduced.
 
db-Centric Lead Developer / (unvested)Shareholder
San Francisco 1997
• Developed a very high performance and advanced SQL tokenizer aware of datamart distribution
I worked for db-Centric as the first employee. The single product builds a virtual database around existing datamarts and foreign DBMS’s. It employs a runtime-conditional server assignment based on SQL WHERE clause, client user, and/or physical location of the client machine. The SQL parser re-writes and optimizes SQL on the fly based on pre-defined business rules that allow your SQL to remain ‘unaware’ of datamart partitioning for large data warehouse implementations. The simple design gives our product a huge performance improvement over competing products (HP’s Intelligent Warehouse). Intricate caching schemes improve efficiency even more. Three programmers including myself created this technology featured by Microsoft in the November 1997 Comdex show. On August 10, 1998 db-Centric was acquired by Aris Corporation, Aris has since become Ciber.
 
The EC Company Consultant
Palo Alto, California 1995 and 1996
• Responsible for product development and the accounting system integrations design
I worked for one of the first business ventures in a category that was initially considered ‘Electronic Commerce’, but years later came to be called B2B. I worked for The EC Company integrating ‘Internet/Application EDI’ with off the shelf and custom accounting systems. My responsibilities included presenting the technology to investors and leading all C++ development. I helped the company grow from 5 to 60 people in 16 months through the initial 3 rounds of financing. At the end of the third financing round I was the 5th largest shareholder.
I developed the award winning client side interface that used RTF to render business documents through a custom built engine that very much resembled a modern XSLT, but this was several years before XSL was even a concept technology. EC Exchange beat the reviews of competing pre-XML B2B products from GEIS and Harbinger according to InfoWorld.
Anderson Consulting and Stanford Research Institute endorsed the technology. The ABA (American Banking Association) briefly adopted the system as a standard of electronic commerce.
The initial success completely changed the founding group, which came to include several prominent forces in Silicon Valley, the technology fell into new ownership, and eventually became licensed by a public company seeking to be a vendor of B2B technology.
 
TRW Financial Systems (DGB Project) Consultant
Oakland, California 1995
• Developed threaded applications for a large Windows NT/Solaris image- messaging system.
This was the first fulltime work I ever did as an independent contractor, a step forward in one degree and also backward as my role in the project was minimal. I came into a project that was nearly complete and in the final stages. In my 6 months there, I developed a much cleaner interface for them and resolved a complex threading deadlock situation that had been a long-standing issue. I also was introduced to a new way of business in Silicon Valley.

 
AMS for AirTouch Cellular Sr. Pgmr Analyst
Lisbon, Portugal (lived in Estoril) 1994
• Developed a framework used by other development teams as the development infrastructure.
I worked for the leading cellular provider in Lisbon, Portugal. I was part of an initial team of senior engineers working for 'American Management Systems' who assessed the effort of converting a VAX cellular customer support application to Windows NT Architecture. We designed an SQL Server, 3-tier architecture (in 1994) that allowed the system to go into production before the entire conversion from the VAX was complete (by abstracting data location). As the only C++ resource on the initial team for several months, I designed and developed the infrastructure of the client application. It had full runtime dynamic multiple language support that could switch labels, buttons, and menus to any of the supported languages, so that it could be used as the basis for all European GSM cellular billing systems.

 
Data Systems, Inc Systems Analyst
Lakewood, Colorado 1993
• Developed a VISA credit system with Verifone card readers communicating to cash registers
________________________________________
 
Resources Trust Company Systems Operations
Englewood, Colorado 1991 and 1992
• Developed automation system for running jobs in the daily interest distribution process

________________________________________
How it began:

My first computer was the TI-99/4A that I got in 1983 when I was 11 years old. It came with a subscription to 99er and Home Computing magazine that published software source code. I typed in some of the short programs and found it fascinating. As my typing improved, I keyed in longer programs and eventually began adjusting variables to see the effect. At 13 years old I could code small programs on my own. Then I acquired an Apple IIe, and with a 300 baud modem I had the world at my fingertips. The modem sounds were a familiar tune from the tape recorder used to store data on the TI-99. I setup a device to record the analog sounds and wrote a small piece of code that set the modem into receive mode, awaiting playback to review an online session from a tape recorder, then I wrote a revolving number dialer to log local modems and let it run over Christmas break from school. Smile | :) At 14 years old I ran my own BBS using school equipment. I was the guru in the school computer club. I did data entry and learned to operate some aspects of accounting while working at a travel agency at the age of 15 and 16. By 17 I was an operator on an IBM System/38 operating a 60 lane grocery store and I was working 40 hours per week. Working the night shift included a majority of idle time, in which I read the manuals and became very proficient in CL. I wrote some scripts to simplify the computer operator job.
At 18 I was hired by Resources Trust Company fulltime as the night computer operator for their AS/400. Immediately I began scripting the automation of the nightly jobs that had to be run. I learned COBOL very quickly and already had some async programming experience. The AS/400 has a system modem that I believe was reserved for remote access by IBM reps, it was not being used for banking operations. With some help, I automated my duties and developed an AS/400 message queue monitor that scanned the system event queues for job messages then dialed out the system Async line, to transmit the information to a text paging service provider. Then I would get a page when the printers were out of paper, because I was hired to keep paper in them not to do any programming. I began experimenting with C++ on PC’s while I was 18, and then got my first job as a real programmer when I was 19. Finally someone was paying me for what I enjoyed to do and would have done for free. At 20 I built a complete event driven GUI operating system for hand held computers used to calibrate precision machinery at NASA and other places. It sported buttons, lists, edits, and context sensitive help within a 640k-memory limit. At 22 I was a senior programmer, very proficient with advanced C++, living in Europe and making $100,000 per year. Then fate led me to Silicon Valley where the real fun began and I formed my 3rd software business, United Business Technologies, at age 23. As of November 2012 and can be reached at: RoaringCheckmate@Live.com
QuestionNeed to support Multi-byte character within GStringmembershunruo26 Jun '12 - 0:49 
ToXML turned Multi-byte character to formated int-string.
AnswerRe: Need to support Multi-byte character within GStringmemberBrian Aberle1 Dec '12 - 7:12 
GStrings store anything, even a JPG image or any data. GStrings are very fast and portable. They do not create link dependancies to Windows. You can #include "GStringCOM.h" for an inlined string implementation that can convert to and from BSTR.
 
This also may help you:
 
#include "afxconv.h"
LPSTR AFXAPI AfxW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars)
LPWSTR AFXAPI AfxA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars)
QuestionThis author is held in jail, please help if you canmemberChandra Mohan S17 Jun '12 - 23:16 
Brian Aberle is serving prison time for exposing police corruption in the state of Georgia, USA. If anyone reading this can help, please do so. Mode details here:
 
http://benjaminfulford.typepad.com/benjaminfulford/2012/06/fw-needing-help-with-internal-affairs.html[^]
AnswerRe: This author is held in jail, please help if you canmemberBrian Aberle1 Dec '12 - 9:01 
I'm out of prison now.
 
Thanks to many concerned individuals that did not want the State of Georgia to murder me for exposing corruption and the FBIs failure to prosecute it properly - I was unexpectedly released from prison early. Everyone has a voice. People who dont even know me like Chandra Mohan and others helped to spread the word about my situation. Some disturbed readers called the authorities. When authorities knew the Internet was watching, they changed their tune.
 
The Judge sentenced me to the maximum time possible. He is a cousin to the Sheriff who I am having all this trouble with. Just a few days ago, that judge recused himself from my case and granted me a new trial. Did the judge have a change of heart? I think not. Some people act different when others are watching. The Internet is watching.
QuestionWhere is the file MFCAbstractions.h?memberChristian Gavin21 Nov '11 - 11:54 
Great framework for XML!
 
I can build and run the "StartHere" sample without a problem, but when I tried to compile "MFCTypesFromXML" I ended up with an error not finding "MFCAbstractions.h". I am using Visual Studio 2008.
 
I looked into both zip files (the one with the samples and the one with the source only) as well as in the SkyDrive and I couldn't find it.
 
Thanks,
Christian
AnswerRe: Where is the file MFCAbstractions.h?memberBrian Aberle1 Dec '12 - 7:24 
The file was renamed to "AbstractionsMFC.h". The sample builds correctly now.
GeneralMy vote of 5memberMihai MOGA22 Sep '11 - 16:00 
Great article. Please keep it up!
QuestionHow to set Object ID from container [modified]memberadin rivera23 Jan '11 - 14:56 
Hi, thanks for your excellent work. The library is very complete and useful.
 
I want to ask you something that I'm not able to figure out yet. Let me explain my situation. I have one container with one list of objects and one list of lists of the same objects. Therefore, I need to check the OID when the objects are created to create a pointer to the objects that were created before. This step I accomplished mapping some fields of the objects into the OID, lets assume that I mapped the name of the object as OID.
 
In each file, the OID is unique, so all the references of the same object are mapped to the same pointer, which is the behavior I'm looking for. However, I have more than one file from which I extract objects. And I need to treat objects from different files as different objects, even if they have the same fields (lets said name).
 
Then my question: Is there a way of map the OID from the container instead of mapping it from the object itself? Or is there a way of sending information from the container to the object to create a OID that is mapped from the container tag (let said the file name which it comes from)? Or is there a way of reading the XML file and signal it that all the objects should be allocated as new objects, but keeping the repeated ones in the same locations?
 
That makes sense? I hope that is possible. I check the examples but I wasn't able to detect something similar to that. I hope you can point me in the right direction.
 
EDIT:
-----
Also, I'm facing another problem now. What can I do to map typedef, unions, and structures? Is there any abstraction. I'm looking all over the place but cannot find any example about it.
 
Regards.

modified on Monday, January 24, 2011 4:39 AM

AnswerRe: How to set Object ID from container [modified]memberBrian Aberle1 Dec '12 - 8:06 
Im sure you have solved this by now, and I cannot positively understand your situation without a code sample but I do have some comments:
 
If two objects have the same OID in two different input files, they apply to the same single instance of that object in memory. For example, Customer 123 may only contain top level data elements when viewed in a list, double clicking it, or viewing details may fire off a query for additional data to add to the single instance of Customer 123. If you are using caching this will happen as default behavior. It is possible to disable caching (do not map an OID) which will cause the previous example to create two instances of Object 123, each with different members that have been assigned - usually not a desired behavior.
 
Yes you can map the OID from another object.
 
Yes you can map a union. A union is simply a compiler safe typecast for mutually exclusive member variable instances of different types. Yes you can map a structure, or more accurately you can map a member in a structure.
 
No you cannot map a typedef. I suspect you do not need to, but feel free to give me an example and see if I can help more.
AnswerRe: How to set Object ID from container [modified]memberBrian Aberle17 Dec '12 - 5:38 
Upon deeper consideration, yes all 3 can be mapped, Unions, Typedefs, and structs. I added this example program to RareUseExamples.
 
class AdvancedDataMaps : public XMLObject
{
public:
	GString m_strString;		// A String Member

	enum DataTypes 
	{ 
		Byte,
		Short,
		Int,
		Int64, 
	} m_DataType;
 
	union STATE_OF_THE_UNION
	{
		char n1Byte;
		short n2Bytes;
		int n4Bytes;
		__int64 n8Bytes;
	}m_MutualExclusion;
 

	struct MEMBER_STATE {
		int N;
		char buf[64];
	}m_State;
 

	virtual void MapXMLTagsToMembers()
	{
		// notice the cast required for the Enum
		MapMember(	(int *)&m_DataType,	"DataType");
 
		// only one of the following may be present in the XML, they are mutually exclusive
		MapMember(	&m_MutualExclusion.n1Byte,	"Byte"); 
		MapMember(	&m_MutualExclusion.n2Bytes,	"Short"); 
		MapMember(	&m_MutualExclusion.n4Bytes,	"Int"); 
		MapMember(	&m_MutualExclusion.n8Bytes,	"Int64"); 
 
		// Objects OR structs of direct containment are mapped directly 
		MapMember(	&m_State.N,	"N");
		MapMember(	m_State.buf,	"buf", sizeof(m_State.buf));
	}
 
	// if the XML contains words that must translate to integer value, as in the case of an enumeration
	virtual void *ObjectMessage( int nCase, const char *pzTagName, const char *pzData, __int64 nDataLen, void *pUnused = 0 )
	{
		// note: the MSG_NON_NUMERIC handler is only required if the xml contains string name 
		// descriptions of the enumerated type, a numeric value will map directly with no need for
		// translation through this overloaded ObjectMessage() handler
		if (nCase == MSG_NON_NUMERIC)
		{
			if (strcmp(pzTagName,"DataType") == 0)
			{
				if (strcmp(pzData,"Byte") == 0)
				{
					// convert from string in the xml to enumerated type in the object
					m_DataType = DataTypes::Byte;
				}
				else if (strcmp(pzData,"Short") == 0)
				{
					m_DataType = DataTypes::Short;
				}
				else if (strcmp(pzData,"Int") == 0)
				{
					m_DataType = DataTypes::Int;
				}
				else if (strcmp(pzData,"Int64") == 0)
				{
					m_DataType = DataTypes::Int64;
				}
			}
		}
		else if (nCase == MSG_MEMBER_UPDATE)
		{
			if (strcmp(pzTagName,"DataType") == 0)
			{
				if (strcmp(pzData,"Byte") == 0)
				{
					SetMemberSerialize("Byte"	,1);
					SetMemberSerialize("Short"	,0);
					SetMemberSerialize("Int"	,0);
					SetMemberSerialize("Int64"	,0);
				}
				else if (strcmp(pzData,"Short") == 0)
				{
					SetMemberSerialize("Byte"	,0);
					SetMemberSerialize("Short"	,1);
					SetMemberSerialize("Int"	,0);
					SetMemberSerialize("Int64"	,0);
				}
				else if (strcmp(pzData,"Int") == 0)
				{
					SetMemberSerialize("Byte"	,0);
					SetMemberSerialize("Short"	,0);
					SetMemberSerialize("Int"	,1);
					SetMemberSerialize("Int64"	,0);
				}
				else if (strcmp(pzData,"Int64") == 0)
				{
					SetMemberSerialize("Byte"	,0);
					SetMemberSerialize("Short"	,0);
					SetMemberSerialize("Int"	,0);
					SetMemberSerialize("Int64"	,1);
				}
			}
		}
		return 0;
	};
	
	DECLARE_FACTORY(AdvancedDataMaps, Maps) 
 
	AdvancedDataMaps(){ ModifyObjectBehavior(MEMBER_UPDATE_NOTIFY); }
	~AdvancedDataMaps(){};
};
IMPLEMENT_FACTORY(AdvancedDataMaps, Maps)
char pzXML4[] = 
"<Maps>"
	"<DataType>Byte</DataType>"
	"<Byte>X</Byte>"
	"<N>777</N>"
	"<Buf>hello world</Buf>"
"</Maps>";
 

char pzXML5[] = 
"<Maps>"
	"<DataType>Int</DataType>"
	"<Int>1234567890</Int>" // 1.2 billion
	"<N>7</N>"
	"<Buf>Global Hello</Buf>"
"</Maps>";
 

void MapUnionStructAndEnum()
{
	AdvancedDataMaps O;
	O.FromXML(pzXML4);
 
	GString strDebug;
	strDebug << "\n\nEnum=" << O.m_DataType << "   Union=" << O.m_MutualExclusion.n1Byte << "\n"
		     << "m_State.N=" << O.m_State.N << "   m_State.buf=" <<  O.m_State.buf << "\n\n";
	printf(strDebug);
///////////////////////////////
//Enum=0   Union=X
//m_State.N=777   m_State.buf=hello world
///////////////////////////////
	
	printf(O.ToXML());
///////////////////////////////
//<Maps>
//	<DataType>0</DataType>
//	<Byte>X</Byte>
//  <N>777</N>
//  <buf>hello world</buf>
//</Maps>	
///////////////////////////////

	// notice that now the XML is pzXML5
	O.FromXML(pzXML5);
	strDebug << "\n\nEnum=" << O.m_DataType << "   Union=" << O.m_MutualExclusion.n4Bytes << "\n"
		     << "m_State.N=" << O.m_State.N << "   m_State.buf=" <<  O.m_State.buf << "\n\n";
	printf(strDebug);
///////////////////////////////
//Enum=2   Union=1234567890
//m_State.N=7   m_State.buf=Global Hello
///////////////////////////////

	printf(O.ToXML());
///////////////////////////////
//<Maps>
//     <DataType>2</DataType>
//     <Int>1234567890</Int>
//     <N>7</N>
//     <buf>Global Hello</buf>
//</Maps>
///////////////////////////////
}

GeneralMy vote of 5memberlipodido17 Jan '11 - 2:43 
Excellent Library
QuestionWhat about std and inheritancememberlipodido17 Jan '11 - 2:29 
First, I want to thank you for this superb library, it help me lot in my works.
I want to use XMLFoundation in a non-intrusive manner because i have already my classes witch use std types ( std ::string and std ::list)
Is there any way to do this without changing all my attributes from string to GString and list to GList etc…
My second question is about Inheritance, I have my class CStudent witch inherit from CPerson I didn’t find any example about doing this (maybe I didn’t search well):
How can I Serialize a CStudent object?
Thank you in advance for your responses.
AnswerRe: What about std and inheritancememberBrian Aberle6 Dec '12 - 5:31 
You raised two excellent questions. Pardon my delay in answering them.
 
I added a file to the project called AbstractionsSTD.h wich has std::list and std::string support. I added a new example called STL to the distribution that shows how to use it.
 
Your second question is also worthy of adding another example, there are many clever ways to use Inheritance in the XMLFoundation. XMLProcedureCall may be too complex of a starting point to study what can be done by calling MapMember() at different levels of inheritance so as I said I will be working on another example program.
AnswerRe: What about std and inheritancememberBrian Aberle17 Dec '12 - 5:34 
I added an example that demonstrates how mapped XML tags use inheritance. Look in RareUseExample program for this example:
 
class CMatter : public XMLObject
{
public:
	GString m_strWeight;
	virtual void MapXMLTagsToMembers()
	{
		MapMember(&m_strWeight,	"Weight");
	}
	DECLARE_FACTORY(CMatter, Matter) 
	CMatter(){} 
	~CMatter(){};
};
IMPLEMENT_FACTORY(CMatter, Matter)
//------------------------------------------------
class CLife : public CMatter 
{
public:
	GString m_strDNA;
	virtual void MapXMLTagsToMembers()
 
	{
		MapMember(	&m_strDNA,	"DNA");
		CMatter::MapXMLTagsToMembers(); // explicit base class call
	}
	
	DECLARE_FACTORY(CLife, Life) 
		CLife(){   }
	~CLife(){};
};
IMPLEMENT_FACTORY(CLife, Life)
//------------------------------------------------
class CHuman : public CLife
{
public:
	GString m_strFingerPrint;
	GString m_strGender;
 
	virtual void MapXMLTagsToMembers()
	{
		MapMember(&m_strFingerPrint,"FingerPrint");
		MapMember(&m_strGender,"Gender");
		CLife::MapXMLTagsToMembers(); // explicit base class call
	}
	
	DECLARE_FACTORY(CHuman, Human) 
 
	CHuman(){} 
	~CHuman(){};
};
IMPLEMENT_FACTORY(CHuman, Human)
//------------------------------------------------
char pzXML3[] = 
"<Human>"
	"<Gender>Male</Gender>"
	"<DNA>1101010001010101101011000010101010</DNA>"
	"<FingerPrint>Unique</FingerPrint>"
	"<Weight>777</Weight>"
"</Human>";
 

 
void MappingAndInheritance()
{
	CHuman O;
	O.FromXMLX(pzXML3);
	
	GString strDebug;
	strDebug << "\n\n\nGender:" << O.m_strGender << "      FingerPrint:" 
			 << O.m_strFingerPrint << "\n" << "DNA:" << O.m_strDNA 
			 << "      Weight:" << O.m_strWeight << "\n\n";
	printf(strDebug);
//////////////////////
// Gender:Male      FingerPrint:Unique
// DNA:1101010001010101101011000010101010      Weight:777	
//////////////////////

 

	printf(O.ToXML());
//////////////////////
//<Human>
//        <FingerPrint>Unique</FingerPrint>
//		  <Gender>Male</Gender>
//        <DNA>1101010001010101101011000010101010</DNA>
//        <Weight>777</Weight>
//</Human>	
//////////////////////

	CLife life;
	//Notice that CLife is being created with pzXML3, that is the 
	//same xml that the CHuman was created with.
	life.FromXML(pzXML3);// Gender and FingerPrint are now unmapped data
	strDebug.Empty();
	strDebug << "\n\nDNA:"	<< life.m_strDNA << "      " 
			 << "Weight:"	<< life.m_strWeight << "\n\n";
	printf(strDebug);
//////////////////////
// DNA:1101010001010101101011000010101010      Weight:777
//////////////////////

 
	printf(life.ToXML());
//////////////////////
//<Life>
//        <DNA>1101010001010101101011000010101010</DNA>
//        <Weight>777</Weight>
//</Life>
//////////////////////

/*
So- for example, you may create an object CPlant that like
the CHuman is derived from CLife.  A CPlant would contain
the elements of CLife (DNA) and of CMatter (Weight) by inheritance.
 
If each XML message represents a transaction it is wise
to map the commonalities of all transactions, or groups of
transactions into a base class that allows derivatives
to inherit the base elements of the transaction that
will only be maintained in one place.
*/
}

GeneralCDATA [modified]memberf56789414 Nov '10 - 10:29 
How do I grab the content of CDATA sections embedded in XML files?
Ex:
 

...
<![CDATA[ ... ]]>

 
The content is a string containing XML forbidden characters only (all printable chars). If it would have been binary data then a GString is just an array of chars so it should work too, but then the content can not be taken out as a const string because any zero will terminate the string.
(Well, Iam not that familiar with GString but std::string it works).
 
virtual void MapXMLTagsToMembers()
{
MapMember(&m_strCDATA, "![CDATA"); // Does not catch <![CDATA[ ... ]]> content
}
 
What MapMember member shall I use to grab CDATA content?
 
Good work!
/stefan
 
Well! I have added this code into xmlObjectFactory.cpp
 
...
else{ /* nothing to do for endtags, and attribute tags */ }
 
/* New code */
if( m_tokenLookAhead.m_type == xml::_cdata){
XMLObjectDataHandler* o = pObjCurrent->GetObjectDataHandler();
if(o){
GString xx;
xx = tok->get();
o->AppendObjectValue(xx);
}
}
/* End new code */
 
if (m_tokenLookAhead.m_type != xml::_unknown)
{
m_pLex->releaseLastToken(&m_tokenLookAhead);
}
 
And it seems to work!
/stefan

modified on Monday, November 15, 2010 2:35 PM

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 21 Dec 2012
Article Copyright 2009 by Brian Aberle
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid