Enabling White-Box Reuse in a Pure Composition Language

  • 775 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
775
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
7
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Enabling White-Box Reuse in a Pure Composition Language Andreas Schlapbach schlpbch@iam.unibe.ch January, 2003.
  • 2. Overview • Introduction – Component-based software development. – Roles of inheritance. – Subclassing as a form of white-box reuse. – Subclassing considered harmful. • Goal – To combine the power of inheritance with the ease of scripting. • Solution – Piccola, our composition language. – Introduce a language extension to JPiccola that enables inheritance. – Implementation and examples. – Applications. • Lessons Learned • Questions & Comments 2
  • 3. Component-based Software Development • Modern applications must be flexible and extendible to adapt to changing require- ments. • These requirements can be addressed best by a component-oriented software devel- opment approach. • Component-oriented software development shifts away from programming towards soft- ware composition. 3
  • 4. Scripting Real-World Components • Applications = Components + Script + a Drop of Glue. • We build applications by scripting compo- nents. • These components must adhere to a com- positional style. • In reality, such components often do not exist. £ We have to adapt existing components, us- ing a drop of glue. 4
  • 5. Adaptation: Black-box versus White-box White-box Reuse. Adapts a mismatched com- ponent by either changing or overriding its internal specification. E.g.: Copy & Paste, Inheritance Black-box Reuse. Adapts the interface of a component only. E.g.: Wrapping techniques, Reflective ap- proach, Standardization 5
  • 6. Roles of Inheritance Inheritance is a key concept of object-oriented languages and plays different roles: Subclassing. At the implementation level, it is a means for code reuse. Subtyping. At the design level, it defines a substitutability relationship. Is-a Relationship. At the conceptual level, it represents a conceptual specialization rela- tionship. These roles of inheritance can conflict. 6
  • 7. Subclassing Considered Harmful • Subclassing can break encapsulation by ac- cessing internal implementation details of an object. • Subclassing introduces subtle dependencies between base and extending classes. • Subclassing is a white-box form of reuse. £ Let’s minimize the use of inheritance. 7
  • 8. Goal: Migrate from Class Inheritance to Object Composition • There are many powerful object-oriented frameworks we would like to reuse as black- box components. • We need inheritance to access their func- tionality. • Our approach is to gain access to the com- ponents of a framework using inheritance, wrap them and script those wrapped com- ponents. £ We would like to have the power of inheri- tance combined with the ease of scripting. 8
  • 9. Piccola • Piccola is a small, pure and general pur- pose scripting language. • Piccola is based on forms, agents and chan- nels: Agents communicate by sending forms along channels. • Forms are extensible records unified with services. Everything is a form. • JPiccola is the Java-based implementation of Piccola. 9
  • 10. A Language Extension for JPiccola We want to use Java frameworks in Piccola using inheritance. Key idea: Create Java objects implementing a given type that delegate all calls to its meth- ods to Piccola services. func(args): ... Java result up(args) down(result) Piccola func(arg1, arg2,...,argn) £ We have to generate classes of a given type at runtime. 10
  • 11. Implementation I The class generation process consists of three steps: 1. Gather information on the structure of the class. 2. Generate the class, using the BCEL byte code engineering library. 3. Load the class into the Java Virtual Ma- chine, using a custom class loader. 11
  • 12. Structure of a Generated Class I Let’s suppose we have class A with a method plus(int i, int j). We define a service plus in Piccola to handle calls to this method. plus(args): ’i = args.at(1) ’j = args.at(2) i + j We generate a subclass of A and redirect the Java call to a Piccola service: public int plus(int j, int j) { Arguments args = new Arguments(); args.add(this); args.add(new Integer(i)); args.add(new Integer(j)); return ((Integer) getService(quot;plusquot;) .callback(args)).intValue(); } 12
  • 13. Structure of a Generated Class II Actually, we generate byte code. Method int plus(int, int) 0 new #22 <Class ch.unibe.piccola.bridge.Arguments> 3 dup 4 invokespecial #23 <Method ch.unibe.piccola.bridge.Arguments()> 7 astore 4 9 aload 4 11 aload_0 12 invokevirtual #27 <Method void add(java.lang.Object)> 15 aload 4 17 new #56 <Class java.lang.Integer> 20 dup 21 iload_1 22 invokespecial #65 <Method java.lang.Integer(int)> 25 invokevirtual #27 <Method void add(java.lang.Object)> 28 aload 4 30 new #56 <Class java.lang.Integer> 33 dup 34 iload_2 35 invokespecial #65 <Method java.lang.Integer(int)> 38 invokevirtual #27 <Method void add(java.lang.Object)> 41 aload_0 42 ldc #75 <String quot;plusquot;> 44 invokevirtual #33 <Method ch.unibe.piccola.IForm getService(java.lang.String)> 47 aload 4 49 invokeinterface (args 2) #39 <InterfaceMethod java.lang.Object callback(ch.unibe.piccola.bridge.Arguments)> 54 checkcast #56 <Class java.lang.Integer> 57 invokevirtual #60 <Method int intValue()> 60 ireturn 13
  • 14. Example I generateSubclassOfA(): newClass name = quot;Bquot; superClassName = quot;Aquot; interfaceNames = [ ] methods = plus = argumentTypeList = [ Type.int, Type.int ] returnType = Type.int body(args): args.at(1) + args.at(2) 14
  • 15. Implementation II Often, we do not need to generate an arbitrary class but implement an interface or generate a direct subclass of an abstract class. £ We can use reflection to gather the infor- mation needed to generate a class. 15
  • 16. Example II generateKeyListener(): newInterface className = quot;java.awt.event.KeyListenerquot; methods = keyPressed(args): println quot;Key Pressedquot; keyReleased(args): println quot;Key Releasedquot; keyTyped(args): println quot;Key Typedquot; 16
  • 17. Applications • Print Service • Scripting an Event Based Parser • Scripting Web Browser Frameworks • GUI Event Composition Style • ... £ We use the language extension whenever we need inheritance. 17
  • 18. Role of Java Interfaces in Frameworks • We seldom generate arbitrary classes, most often we just implement Java interfaces. Why is this? • A framework consists of ready-to-use and half finished building blocks. • While most parts are stable, it permits its user to adapt parts of it according to their needs. These are the hot spots of a frame- work. • Superior to (abstract) classes, interfaces do not impose a specific inheritance hier- archy. £ Java interfaces provide a good way to con- trol the type of adaptations compatible with a framework. 18
  • 19. Closing Remarks • The language extension integrates nicely into JPiccola. • Good components are hard to find. • A framework is more than a bundle of classes. 19
  • 20. Questions & Comments 20
  • 21. ClassFile ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; } 21