设为首页】 【加入收藏】 【网站地图】 【商品折扣
娱乐一生 娱乐明星
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
首页  |  java  |  .NET  |  C/C++  |  网页技术  |  php  |  asp  |  delphi  |  VC  |  VB开发  |  游戏开发  |  软件工程  |  Power Builder  |  Linux开发  |  Windows开发技巧
当前位置:首页 >> JAVA与XML >> Translation-Based Integration @ JDJ

Translation-Based Integration @ JDJ -

Anyone who regularly works with more than one development language and a third-party library has faced the situation described by: "Great library, if only I could have it in my programming language." Some vendors make a living from publishing different language versions of their product, but many can't afford or don't want to pay the costs of maintaining several parallel implementations of their product.

Consequently, over the years many integration approaches have been created to help us with the common problem of using software written in one language in another language. Microsoft has even gone as far as building language inter-operability into the core of its .NET platform (of course, they excluded Java). When talking about .NET, it should also be mentioned that a .NET-compatible language has to satisfy many constraints imposed by the .NET platform. So many constraints, in fact, that some people have said you don't really write your code in C++ or VB, but rather in a particular dialect of .NET. For anybody who is not using .NET, or who has to integrate .NET with .NET-foreign languages such as Java, here are the basic integration approaches:

  1. Source code translation: Translate the Java source code of a library to C++.
  2. Byte code/binary code translation: Take a compiled Java class file and compile it into object code. This, as well as the previous approach, can also be referred to as "implementation translation," because the method bodies are converted.
  3. In-process wrapping: Create a C++ wrapper for a Java type that internally uses JNI to delegate from C++ to Java.
  4. Out-of-process wrapping (remoting): Make a Java type available to a C++ programmer by calling from the C++ application into a Java process via sockets. This, as well as the previous approach, can also be referred to as "interface translation," because only the API signatures are converted.
  5. RPC/Web services/messaging: This is really a special case of (4) and involves the sending of messages between applications written in different languages. SOAP, CORBA, XML RPC, etc., are examples of this integration approach.
All of these different integration approaches have one thing in common - to work for a reasonably large code library or API, an automated translation/transformation engine is an absolute must. Imagine having to translate the Java runtime library to C++ by hand or having to hand-assemble and dispatch a SOAP request in a C++ program just to call a Java method.

Also, let's not forget that this type of integration problem does not start out with a portable interface description like CORBA's IDL or Web services' WSDL, but rather with a full, preexisting implementation in one of many possible technologies.

Let's take a quick look at some factors that influence our choice of integration technology before we delve into the more technical aspects. I haven't listed these points by importance; which points are important to you depends entirely on your specific integration project.

Granularity
At what level do we integrate? If we are dealing with a component API, i.e., an API that has relatively few integration points for relatively hefty operations, an RPC-based integration could be a good fit.

Performance
If we need fine-grained integration at the API level, any RPC-based solution is usually ruled out because we cross the language boundary too often for too little work, resulting in bad performance.

Reliability
Any out-of-process/RPC solution introduces new failure modes into an overall solution. Can you create a reliable integration solution for the specific API that you wish to use? If the answer is yes, how much more complicated is it going to be?

Security
Is an out-of-process/RPC solution without additional security mechanisms acceptable for your integration problem? Is additional security available and how much is it going to complicate the project or increase the price?

Scalability
In-process integration solutions usually have the best performance by far, but they may be wasteful in terms of system resources, and scalability might benefit from being able to distribute integration components. On the other hand, some APIs cannot be distributed/remoted without jeopardizing reliability.

Fidelity
How true to the original should the integration API be? Should it be self-evident to a user of the original API or are some special skills (like JNI, CORBA, or SOAP) required?

Purity
Is it necessary to completely remove the original technology from the picture (i.e., by translating/porting the code) or can we bridge between the two sides? Bridging might be the only feasible solution if you don't have access to all the referenced pieces (for example, a source code translator does not work if the code that needs to be translated references a third-party library for which you don't have the source code).

Licensing
This is often an issue for translation-based tools: even if you can translate your own code for an integration solution, do you have the necessary rights to translate referenced source code (for example, from a J2SE source distribution)?

Maintenance
Is your integration solution tied to a specific version of a technology and how easy is it to regenerate the integration solution and upgrade to a new version of the technology?

Clearly, given an API in one language, we would love to have the following: an automatically generated, highly reliable, totally secure, highly performing, true-to-the-original, semantically equivalent API in the other language. World peace would be another nice thing to have, while we're at it.

In the real world, of course, things are not that simple. I always like using Java and C++ as an example - first, because I know a lot about these two languages and, second, because they are deceptively similar. Many people think that it should be simple to translate an application written in one language into the other language. Let's take a closer look at this. The Java class in the following code will be our first example.

public class Person
{
  public String	name;
  public Person() { name = null; }
  public Person( Person p ) { name = p.name; }
  public String getName() { return name; }
  public void   setName( String n ) { name = n; }
  public static void  delete( Person p ) { PersonUtil.delete( p.name );
  public static Person create( String n ) { return new Person( n ); }
}

This is a fairly straightforward Java class. The only slightly unusual thing about it is its public data member called name. Maybe we were forced to make it public because we're using this type with a JavaSpace or we might simply have made it public due to a design oversight.

Now let's cook up a C++ class that does the same thing. That should be easy, shouldn't it? We could probably write a simple parser and translator and come up with the automatically generated C++ type in the following.

class Person
{
public:
  std::string      name;
  Person() : name() {}
  Person( const Person & p ) : name( p.name ) {}
  ~Person() {}
  std::string      getName() { return name; }
  void             setName( std::string n ) { name = n }
  static void      delete( Person & p )
  {
    PersonUtil::delete( p.name );
  }
  static Person    create( std::string n )
  {
    return Person( n );
  }
};

That's a straightforward look-alike of the original Java type in C++. We'll have at least one immediately obvious problem here: delete is a reserved word in C++, so the generated code won't compile. In the case of delete this is an easily solved problem; we simply use _delete or some other mangled form of the reserved word. The ease of solving this problem hides a deeper problem though: C++ has a preprocessor that usually predefines many macros. Each of those macros really has to be treated like a reserved word, and that is going to be complicated without a sophisticated tool.

Then there is a host of less obvious problems with this na?ve translation. Let's go through them one by one.

1.  We translated the Java Person( Person ) constructor into the C++ copy constructor. This is totally appropriate based on its call signature, but it might not be appropriate semantically. The C++ copy constructor is invoked automatically by the compiler in many scenarios, whereas the original Java constructor is only supposed to be invoked explicitly by the programmer. Will our generated code have the correct semantics? It depends on the type, which is usually not a satisfactory answer.
2.  In Java, we had a string field; in C++ we have a corresponding std::string field. There's another semantic difference hidden in this seemingly obvious translation: String instances are immutable, whereas std::string instances can be modified. Yes, we could try working with const or mutable modifiers, but those modifiers might collide with other intended semantic usages.
3.  The create method in the Java class returns a new Person instance. We're facing the question of what to return from the corresponding C++ method. If we return the Person instance by value as in the sample code, we make sure that it does not get created on the heap and that we don't have a memory leak if we ignore the return value (something that's usually safe to do in garbage collecting Java). The downside of this approach is that we end up with an instance of class Person. We can now never return a subtype of Person from this method unless we return the result through a pointer to Person or a reference to Person. But if we return the result via a pointer, we put the burden of freeing the instance on the caller, which is a built-in memory leak as the return value is usually ignored on the Java side. This demonstrates how a perfectly correct and proper translation can yield either semantically incorrect or semantically hard-to-use code. It's a true catch 22.
4.  In the delete method, we're calling into the PersonUtil type. This means we have to translate this as well, or make it available in some other fashion in order for the integration project to be a success. In a typical integration project, you quickly face a type explosion due to these dependencies. For example, if you analyze the Java type object, you find out that it references (directly or indirectly) between 250 and 350 types. A good translation-based integration tool will allow you to prune down the type set to just the types that you're interested in without compromising usability.

Other big semantic issues in a Java/C++ translation involve:

  • Inheritance semantics (is inheritance allowed or not)
  • Exception semantics (C++ exception declarations have very different semantics from Java exception declarations)
  • Interface semantics
  • Life cycle management and copy semantics
  • Thread semantics
Just translating a Java statement to a corresponding C++ statement rarely does the job. The problem is mostly not the syntax differences between the two languages but rather the semantic differences between the languages. Also think about the work that might be required to replace the platform infrastructure like the String class. In Java, String has a lot of functionality; how much depends on which version of String you're looking at. If we simply translate String to std::string, what's going to happen to the original Java functionality of String?

The point I'm trying to make is that na?ve translations very quickly run into lots of problems unless the translated API is very small. Where does this leave us? It leaves us with two basic options.

1. Put the semantic integration burden on the user
This is the path that most EAI strategies like Web services or CORBA take. The user creates what amounts to an integration model (IDL, WSDL) and implements it in terms of his or her favorite technology.

Some tools can help by generating integration models based on existing code, but, as I already pointed out, this is a tricky proposition because some semantic usability (extensibility, life-cycle, etc.) cannot be expressed in your integration model of choice. Also as already mentioned, this approach works best for component models with relatively few and relatively simple entry points. Simple means that you don't have many complex, user-defined or platform types, but rather primitive types or pseudo-primitive types, like String or Date.

2. Put the semantic integration burden on the translation tool
This is the path that is taken by some integration solutions that are exclusively targeting language-integration problems. These tools create very sophisticated type models that mirror (to the extent possible) the underlying type model.

The developer can use arbitrarily complex user- or platform-defined types as if they were written in his or her language.

In my opinion, the latter alternative is the better one because it avoids the pitfalls of having to constantly maintain an integration model and because the "unexpected" API differences are small. The more a developer has to learn when using a type that is written in a different language, the less successful the integration technology is going to be. Any special knowledge that is required creates "friction," and friction causes bugs, and bugs cost money and cause the tool to be unpopular.

I believe that the automated translation of code (source or object) into another language, be it an implementation translation or a calling interface translation, is the way to go for language integration.



 

娱乐图摘

更多 >>

靓丽清纯美女meimei

美女私房全裸照
导演劝女演员脱衣服(视频)

大胆火辣人体艺术写真(图)

黑丝妹妹热辣诱惑-丝袜美女妹妹

PLMM 漂亮妹妹图集-妹妹图库

全球美女图库-美女集中营

52MM 我爱漂亮妹妹-制服妹妹诱惑

图王图库-世界美女明星图片资料库
美女写真集锦

激情两性-解密性生活
浴室MM湿身内衣诱惑
邻家小妹洗澡被偷拍(视频)

热点文章

更多

· Eclipse Plugins Exposed, Part
· Enterprise Web Services Securi
· Portlets and Portals Design Ov
· 实现电子商务的可伸缩性和高可用性--BEA WebLogic
· Getting the Most from the MX C
· XML DTD for EJB Deployment Des
· A Dozen Ways to Get the Testi
· XQuery Not Necessarily the Dea
· AXIS学习笔记(一)
· Java程序文件格式设计

热点文章

更多