1 of 63

Principles of Software Construction: Objects, Design, and Concurrency��Libraries and Frameworks

(Design for large-scale reuse)

Jeremy Lacomis and Christian Kaestner

1

17-214/514

2 of 63

Administrivia

  • No class on Tuesday, it’s Democracy Day (please vote if you can)
  • The next midterm is on Thursday. We will release a sample midterm in the next few days.
  • If you haven’t started HW5 yet and you didn’t do Lab 8, please don’t use your coupon with your school email.

2

17-214/514

3 of 63

Quiz

https://bit.ly/214Q13

3

17-214/514

4 of 63

Name three things that make designing distributed systems more challenging than designing a purely local system.

4

17-214/514

5 of 63

Suppose you are designing a system that has three components, A, B, and C such that A.foo() calls B.bar() which in turn calls C.baz(). To follow the best practices of modular protection, where is the best place for an exception that occurs inside of C.baz() to be handled?

5

17-214/514

6 of 63

Learning goals for today

  • Describe example well-known example frameworks
  • Know key terminology related to frameworks
  • Know common design patterns in different types of frameworks
  • Discuss differences in design trade-offs for libraries vs. frameworks
  • Analyze a problem domain to define commonalities and extension points (cold spots and hot spots)
  • Analyze trade-offs in the use vs. reuse dilemma
  • Know common framework implementation choices

6

17-214/514

7 of 63

Where Does That Get Us?

Subtype Polymorphism ✓

Information Hiding, Contracts ✓

Immutability ✓

Types ✓

Unit Testing ✓

Domain Analysis ✓

Inheritance & Del. ✓

Responsibility�Assignment,�Design Patterns,�Antipattern ✓

Promises/�Reactive P. ✓

Integration Testing ✓

GUI vs Core ✓

Frameworks and Libraries, APIs

Module systems,�microservices

(Testing for) Robustness

CI ✓, DevOps, Teams

Design for

understanding

change/ext.

reuse

robustness

...

Small scale:

One/few objects

Mid scale:

Many objects

Large scale:

Subsystems

7

17-214/514

8 of 63

Earlier in this course: Class-level reuse

Language mechanisms supporting reuse

  • Inheritance
  • Subtype polymorphism (dynamic dispatch)
  • Parametric polymorphism (generics)*

Design principles supporting reuse

  • Small interfaces
  • Information hiding
  • Low coupling
  • High cohesion

Design patterns supporting reuse

  • Template method, decorator, strategy, composite, adapter, …

* Effective Java items 26, 29, 30, and 31

8

17-214/514

9 of 63

Where Does That Get Us?

Subtype Polymorphism ✓

Information Hiding, Contracts ✓

Immutability ✓

Types ✓

Unit Testing ✓

Domain Analysis ✓

Inheritance & Del. ✓

Responsibility�Assignment,�Design Patterns,�Antipattern ✓

Promises/�Reactive P. ✓

Integration Testing ✓

GUI vs Core ✓

Frameworks and Libraries, APIs

Module systems,�microservices

(Testing for) Robustness

CI ✓, DevOps, Teams

Design for

understanding

change/ext.

reuse

robustness

...

Small scale:

One/few objects

Mid scale:

Many objects

Large scale:

Subsystems

9

17-214/514

10 of 63

Today: Reuse at scale

  • Examples, terminology
  • Whitebox and blackbox frameworks
  • Design considerations
  • Implementation details
    • Responsibility for running the framework
    • Loading plugins

10

17-214/514

11 of 63

Reuse and variation: �Family of development tools

11

17-214/514

12 of 63

Reuse and variation: �Visual Studio Code Extensions

12

17-214/514

13 of 63

Reuse and variation: Web browser extensions

13

17-214/514

14 of 63

Reuse and variation: �Flavors of Linux

14

17-214/514

15 of 63

Reuse and variation: �Product lines

15

17-214/514

16 of 63

Today: Reuse at scale

  • Examples, terminology
  • Whitebox and blackbox frameworks
  • Design considerations
  • Implementation details
    • Responsibility for running the framework
    • Loading plugins

16

17-214/514

17 of 63

Terminology: Library

  • Library: A set of classes and methods that provide reusable functionality
  • Client calls library; library executes and returns data
  • Client controls
    • Program structure
    • Control flow

  • E.g.: Math, Collections, I/O, command line parsing

Library

public MyWidget extends JContainer {

public MyWidget(int param) {

// setup internals, without rendering

}

// render component on first view and resizing

protected void paintComponent(Graphics g) {

// draw a red box on his component

Dimension d = getSize();

g.setColor(Color.red);

g.drawRect(0, 0, d.getWidth(), d.getHeight());

}

}

your code

17

17-214/514

18 of 63

Terminology: Frameworks

  • Framework: Reusable skeleton code that can be customized into an application
  • Framework calls back into client code
    • The Hollywood principle: “Don’t call us. We’ll call you.”
  • Framework controls
    • Program structure
    • Control flow

  • E.g.: VSCode, Firefox, IntelliJ, NanoHttpd, Express, Android, React?

Framework

public MyWidget extends JContainer {

public MyWidget(int param) {

// setup internals, without rendering

}

// render component on first view and resizing

protected void paintComponent(Graphics g) {

// draw a red box on his component

Dimension d = getSize();

g.setColor(Color.red);

g.drawRect(0, 0, d.getWidth(), d.getHeight());

}

}

your code

18

17-214/514

19 of 63

A calculator example (without a framework)

public class Calc extends JFrame {

private JTextField textField;

public Calc() {

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText("calculate");

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

textField.setText("10 / 2 + 6");

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textfield, BorderLayout.WEST);

button.addActionListener(/* calculation code */);

this.setContentPane(contentPane);

this.pack();

this.setLocation(100, 100);

this.setTitle("My Great Calculator");

...

}

}

19

17-214/514

20 of 63

A simple example framework

  • Consider a family of programs consisting of a button and text field only:

  • What source code might be shared?

20

17-214/514

21 of 63

A calculator example (without a framework)

public class Calc extends JFrame {

private JTextField textField;

public Calc() {

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText("calculate");

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

textField.setText("10 / 2 + 6");

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textfield, BorderLayout.WEST);

button.addActionListener(/* calculation code */);

this.setContentPane(contentPane);

this.pack();

this.setLocation(100, 100);

this.setTitle("My Great Calculator");

...

}

}

21

17-214/514

22 of 63

A simple example framework

public abstract class Application extends JFrame {

protected String getApplicationTitle() { return ""; }

protected String getButtonText() { return ""; }

protected String getInitialText() { return ""; }

protected void buttonClicked() { }

private JTextField textField;

public Application() {

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText(getButtonText());

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

textField.setText(getInitialText());

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textField, BorderLayout.WEST);

button.addActionListener((e) -> { buttonClicked(); });

this.setContentPane(contentPane);

this.pack();

this.setLocation(100, 100);

this.setTitle(getApplicationTitle());

...

}

22

17-214/514

23 of 63

Using the example framework

public abstract class Application extends JFrame {

protected String getApplicationTitle() { return ""; }

protected String getButtonText() { return ""; }

protected String getInitialText() { return ""; }

protected void buttonClicked() { }

private JTextField textField;

public Application() {

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText(getButtonText());

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

textField.setText(getInitialText());

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textField, BorderLayout.WEST);

button.addActionListener((e) -> { buttonClicked(); });

this.setContentPane(contentPane);

this.pack();

this.setLocation(100, 100);

this.setTitle(getApplicationTitle());

...

}

public class Calculator extends Application {

protected String getApplicationTitle() { return "My Great Calculator"; }

protected String getButtonText() { return "calculate"; }

protected String getInititalText() { return "(10 – 3) * 6"; }

protected void buttonClicked() {

JOptionPane.showMessageDialog(this, "The result of " + getInput() +

" is " + calculate(getInput()));

}

private String calculate(String text) { ... }

}

23

17-214/514

24 of 63

Using the example framework again

public abstract class Application extends JFrame {

protected String getApplicationTitle() { return ""; }

protected String getButtonText() { return ""; }

protected String getInitialText() { return ""; }

protected void buttonClicked() { }

private JTextField textField;

public Application() {

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText(getButtonText());

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

textField.setText(getInitialText());

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textField, BorderLayout.WEST);

button.addActionListener((e) -> { buttonClicked(); });

this.setContentPane(contentPane);

this.pack();

this.setLocation(100, 100);

this.setTitle(getApplicationTitle());

...

}

public class Ping extends Application {

protected String getApplicationTitle() { return "Ping"; }

protected String getButtonText() { return "ping"; }

protected String getInititalText() { return "127.0.0.1"; }

protected void buttonClicked() { ... }

}

24

17-214/514

25 of 63

General distinction: Library vs. framework

Library

Framework

public MyWidget extends JContainer {

ublic MyWidget(int param) {/ setup internals, without rendering

}

/ render component on first view and resizing

protected void paintComponent(Graphics g) {

// draw a red box on his componentDimension d = getSize();

g.setColor(Color.red);

g.drawRect(0, 0, d.getWidth(), d.getHeight()); }

}

public MyWidget extends JContainer {

ublic MyWidget(int param) {/ setup internals, without rendering

}

/ render component on first view and resizing

protected void paintComponent(Graphics g) {

// draw a red box on his componentDimension d = getSize();

g.setColor(Color.red);

g.drawRect(0, 0, d.getWidth(), d.getHeight()); }

}

your code

user

interacts

your code

user

interacts

25

17-214/514

26 of 63

Libraries and frameworks in practice

  • Defines key abstractions and their interfaces
  • Defines object interactions and invariants
  • Defines flow of control
  • Provides architectural guidance
  • Provides defaults

framework library

framework

application

credit: Erich Gamma

26

17-214/514

27 of 63

Framework vs. Library

We already saw some examples of frameworks:

  • Visual Studio Code
  • Web browsers

What about these?

27

17-214/514

28 of 63

Is Express a framework or a library?

Click Present with Slido or install our Chrome extension to activate this poll while presenting.

28

17-214/514

29 of 63

Is Handlebars a framework or a library?

Click Present with Slido or install our Chrome extension to activate this poll while presenting.

29

17-214/514

30 of 63

Is Santorini a Framework?

30

17-214/514

31 of 63

More terms

  • API: Application Programming Interface, the interface of a library or framework
  • Client: The code that uses an API
  • Plugin: Client code that customizes a framework
  • Extension point: A place where a framework supports extension with a plugin

31

17-214/514

32 of 63

More terms

  • Protocol: The expected sequence of interactions between the API and the client
  • Callback: A plugin method that the framework will call to access customized functionality
  • Lifecycle method: A callback method that gets called in a sequence according to the protocol and the state of the plugin

32

17-214/514

33 of 63

Today: Libraries and frameworks for reuse

  • Terminology and examples
  • Whitebox and blackbox frameworks
  • Designing a framework
  • Implementation details

33

17-214/514

34 of 63

WHITE-BOX VS BLACK-BOX* FRAMEWORKS

* outdated terms, not aware of common replacements; maybe Inheritance-Based vs Delegation-Based Frameworks

34

17-214/514

35 of 63

Whitebox (inheritance-based) frameworks

  • Extension via subclassing and overriding methods
  • Common design pattern(s):
    • Template method
  • Subclass has main method but gives control to framework

35

17-214/514

36 of 63

Blackbox (delegation-based) frameworks

  • Extension via implementing a plugin interface
  • Common design pattern(s):
    • Strategy
    • Command
    • Observer
  • Plugin-loading mechanism loads plugins and gives control to the framework

36

17-214/514

37 of 63

Is this a whitebox or blackbox framework?

public abstract class Application extends JFrame {

protected String getApplicationTitle() { return ""; }

protected String getButtonText() { return ""; }

protected String getInitialText() { return ""; }

protected void buttonClicked() { }

private JTextField textField;

public Application() {

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText(getButtonText());

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

textField.setText(getInitialText());

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textField, BorderLayout.WEST);

button.addActionListener((e) -> { buttonClicked(); });

this.setContentPane(contentPane);

this.pack();

this.setLocation(100, 100);

this.setTitle(getApplicationTitle());

...

}

public class Calculator extends Application {

protected String getApplicationTitle() { return "My Great Calculator"; }

protected String getButtonText() { return "calculate"; }

protected String getInititalText() { return "(10 – 3) * 6"; }

protected void buttonClicked() {

JOptionPane.showMessageDialog(this, "The result of " + getInput() +

" is " + calculate(getInput()));

}

private String calculate(String text) { ... }

}

public class Ping extends Application {

protected String getApplicationTitle() { return "Ping"; }

protected String getButtonText() { return "ping"; }

protected String getInititalText() { return "127.0.0.1"; }

protected void buttonClicked() { ... }

}

37

17-214/514

38 of 63

An example blackbox framework

public class Application extends JFrame {

private JTextField textField;

private Plugin plugin;

public Application() { }

protected void init(Plugin p) {

p.setApplication(this);

this.plugin = p;

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText(plugin != null ? plugin.getButtonText() : "ok");

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

if (plugin != null) textField.setText(plugin.getInititalText());

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textField, BorderLayout.WEST);

if (plugin != null)

button.addActionListener((e) -> { plugin.buttonClicked(); } );

this.setContentPane(contentPane);

...

}

public String getInput() { return textField.getText(); }

}

public interface Plugin {

String getApplicationTitle();

String getButtonText();

String getInititalText();

void buttonClicked() ;

void setApplication(Application app);

}

38

17-214/514

39 of 63

An example blackbox framework

public class Application extends JFrame {

private JTextField textField;

private Plugin plugin;

public Application() { }

protected void init(Plugin p) {

p.setApplication(this);

this.plugin = p;

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText(plugin != null ? plugin.getButtonText() : "ok");

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

if (plugin != null) textField.setText(plugin.getInititalText());

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textField, BorderLayout.WEST);

if (plugin != null)

button.addActionListener((e) -> { plugin.buttonClicked(); } );

this.setContentPane(contentPane);

...

}

public String getInput() { return textField.getText(); }

}

public interface Plugin {

String getApplicationTitle();

String getButtonText();

String getInititalText();

void buttonClicked() ;

void setApplication(Application app);

}

public class CalcPlugin implements Plugin {

private Application app;

public void setApplication(Application app) { this.app = app; }

public String getButtonText() { return "calculate"; }

public String getInititalText() { return "10 / 2 + 6"; }

public void buttonClicked() {

JOptionPane.showMessageDialog(null, "The result of "

+ app.getInput() + " is "

+ calculate(app.getInput()));

}

public String getApplicationTitle() { return "My Great Calculator"; }

}

39

17-214/514

40 of 63

An aside: Plugins could be reusable too…

public class Application extends JFrame implements InputProvider {

private JTextField textField;

private Plugin plugin;

public Application() { }

protected void init(Plugin p) {

p.setApplication(this);

this.plugin = p;

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

button.setText(plugin != null ? plugin.getButtonText() : "ok");

contentPane.add(button, BorderLayout.EAST);

textField = new JTextField("");

if (plugin != null) textField.setText(plugin.getInititalText());

textField.setPreferredSize(new Dimension(200, 20));

contentPane.add(textField, BorderLayout.WEST);

if (plugin != null)

button.addActionListener((e) -> { plugin.buttonClicked(); } );

this.setContentPane(contentPane);

...

}

public String getInput() { return textField.getText(); }

}

public interface Plugin {

String getApplicationTitle();

String getButtonText();

String getInititalText();

void buttonClicked() ;

void setApplication(InputProvider app);

}

public class CalcPlugin implements Plugin {

private InputProvider app;

public void setApplication(InputProvider app) { this.app = app; }

public String getButtonText() { return "calculate"; }

public String getInititalText() { return "10 / 2 + 6"; }

public void buttonClicked() {

JOptionPane.showMessageDialog(null, "The result of "

+ app.getInput() + " is "

+ calculate(app.getInput()));

}

public String getApplicationTitle() { return "My Great Calculator"; }

}

public interface InputProvider {

String getInput();

}

40

17-214/514

41 of 63

Frameworks summary

  • Whitebox frameworks use subclassing
    • Allows extension of every nonprivate method
    • Need to understand implementation of superclass
    • Only one extension at a time
    • Compiled together
    • Often so-called developer frameworks
  • Blackbox frameworks use composition
    • Allows extension of functionality exposed in interface
    • Only need to understand the interface
    • Multiple plugins
    • Often provides more modularity
    • Separate deployment possible (.jar, .dll, …)
    • Often so-called end-user frameworks, platforms

41

17-214/514

42 of 63

Framework design considerations

  • Once designed there is little opportunity for change
  • Key decision: Separating common parts from variable parts
    • What problems do you want to solve?
  • Possible problems:
    • Too few extension points: Limited to a narrow class of users
    • Too many extension points: Hard to learn, slow to extend
    • Too generic: Little reuse value

42

17-214/514

43 of 63

USE VS REUSE:�DOMAIN ENGINEERING

43

17-214/514

44 of 63

44

17-214/514

45 of 63

(one modularization: tangrams)

45

17-214/514

46 of 63

Tangrams

46

17-214/514

47 of 63

The use vs. reuse dilemma

  • Large rich components are very useful, but rarely fit a specific need
  • Small or extremely generic components often fit a specific need, but provide little benefit

“maximizing reuse minimizes use”

C. Szyperski

47

17-214/514

48 of 63

Domain engineering

  • Understand users/customers in your domain: What might they need? What extensions are likely?
  • Collect example applications before designing a framework
  • Make a conscious decision what to support (scoping)
  • e.g., the Eclipse policy:
    • Plugin interfaces are internal at first
      • Unsupported, may change
    • Public stable extension points created when there are at least two distinct customers

48

17-214/514

49 of 63

The cost of changing a framework

public class Application extends JFrame {

private JTextField textfield;

private Plugin plugin;

public Application(Plugin p) { this.plugin=p; p.setApplication(this); init(); }

protected void init() {

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

if (plugin != null)

button.setText(plugin.getButtonText());

else

button.setText("ok");

contentPane.add(button, BorderLayout.EAST);

textfield = new JTextField("");

if (plugin != null)

textfield.setText(plugin.getInititalText());

textfield.setPreferredSize(new Dimension(200, 20));

contentPane.add(textfield, BorderLayout.WEST);

if (plugin != null)

button.addActionListener(/* … plugin.buttonClicked();… */);

this.setContentPane(contentPane);

}

public String getInput() { return textfield.getText();}

}

public class CalcPlugin implements Plugin {

private Application application;

public void setApplication(Application app) { this.application = app; }

public String getButtonText() { return "calculate"; }

public String getInititalText() { return "10 / 2 + 6"; }

public void buttonClicked() {

JOptionPane.showMessageDialog(null, "The result of "

+ application.getInput() + " is "

+ calculate(application.getText())); }

public String getApplicationTitle() { return "My Great Calculator"; }

}

public interface Plugin {

String getApplicationTitle();

String getButtonText();

String getInititalText();

void buttonClicked() ;

void setApplication(Application app);

}

49

17-214/514

50 of 63

The cost of changing a framework

public class Application extends JFrame {

private JTextField textfield;

private Plugin plugin;

public Application(Plugin p) { this.plugin=p; p.setApplication(this); init(); }

protected void init() {

JPanel contentPane = new JPanel(new BorderLayout());

contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

JButton button = new JButton();

if (plugin != null)

button.setText(plugin.getButtonText());

else

button.setText("ok");

contentPane.add(button, BorderLayout.EAST);

textfield = new JTextField("");

if (plugin != null)

textfield.setText(plugin.getInititalText());

textfield.setPreferredSize(new Dimension(200, 20));

contentPane.add(textfield, BorderLayout.WEST);

if (plugin != null)

button.addActionListener(/* … plugin.buttonClicked();… */);

this.setContentPane(contentPane);

}

public String getInput() { return textfield.getText();}

}

public class CalcPlugin implements Plugin {

private Application application;

public void setApplication(Application app) { this.application = app; }

public String getButtonText() { return "calculate"; }

public String getInititalText() { return "10 / 2 + 6"; }

public void buttonClicked() {

JOptionPane.showMessageDialog(null, "The result of "

+ application.getInput() + " is "

+ calculate(application.getText())); }

public String getApplicationTitle() { return "My Great Calculator"; }

}

public interface Plugin {

String getApplicationTitle();

String getButtonText();

String getInititalText();

void buttonClicked() ;

void setApplication(Application app);

}

Consider adding an extra method.

50

17-214/514

51 of 63

Learning a framework

  • Documentation
  • Tutorials, wizards, and examples
  • Communities, email lists and forums
  • Other client applications and plugins

effort

reward

Library

Framework

51

17-214/514

52 of 63

Typical framework design and implementation

Define your domain

Identify potential common parts and variable parts

Design and write sample plugins/applications

Factor out & implement common parts as framework

Provide plugin interface & callback mechanisms for variable parts

Use well-known design principles and patterns where appropriate…

Get lots of feedback, and iterate

52

17-214/514

53 of 63

FRAMEWORK MECHANICS

53

53

17-214/514

54 of 63

Running a framework

  • Some frameworks are runnable by themselves
    • e.g. Eclipse, VSCode, IntelliJ
  • Other frameworks must be extended to be run
    • MapReduce, Swing, JUnit, NanoHttpd, Express

54

17-214/514

55 of 63

Methods to load plugins

1. Client writes main function, creates a plugin object, and passes it to framework

(see blackbox example above)

2. Framework has main function, client passes name of plugin as a command line argument or environment variable

(see next slide)

3. Framework looks in a magic location

Config files or .jar/.js files in a plugins/ directory are automatically loaded and processed

4. GUI for plugin management

E.g., web browser extensions

55

17-214/514

56 of 63

An example plugin loader using Java Reflection

public static void main(String[] args) {

if (args.length != 1)

System.out.println("Plugin name not specified");

else {

String pluginName = args[0];

try {

Class<?> pluginClass = Class.forName(pluginName);

new Application((Plugin) pluginClass.newInstance()).setVisible(true);

} catch (Exception e) {

System.out.println("Cannot load plugin " + pluginName

+ ", reason: " + e);

}

}

}

56

17-214/514

57 of 63

An example plugin loader in Node.js

const args = process.argv

if (args.length < 3)

console.log("Plugin name not specified");

else {

const plugin = require("plugins/"+args[2]+".js")()

startApplication(plugin)

}

57

17-214/514

58 of 63

Another plugin loader using Java Reflection

public static void main(String[] args) {

File config = new File(".config");

BufferedReader reader = new BufferedReader(new FileReader(config));

Application = new Application();

Line line = null;

while ((line = reader.readLine()) != null) {

try {

Class<?> pluginClass = Class.forName(line);

application.addPlugin((Plugin) pluginClass.newInstance());

} catch (Exception e) {

System.out.println("Cannot load plugin " + line

+ ", reason: " + e);

}

}

reader.close();

application.setVisible(true);

}

58

17-214/514

59 of 63

GUI-based plugin management

59

17-214/514

60 of 63

Supporting multiple plugins

  • Observer design pattern is commonly used
  • Load and initialize multiple plugins
  • Plugins can register for events
  • Multiple plugins can react to same�events
  • Different interfaces for different events possible

public class Application {

private List<Plugin> plugins;

public Application(List<Plugin> plugins) {

this.plugins=plugins;

for (Plugin plugin: plugins)

plugin.setApplication(this);

}

public Message processMsg (Message msg) {

for (Plugin plugin: plugins)

msg = plugin.process(msg);

...

return msg;

}

}

60

17-214/514

61 of 63

Example: A VS Code Extension

61

17-214/514

62 of 63

Example: A JUnit Plugin

public class SampleTest {

private List<String> emptyList;

@Before

public void setUp() {

emptyList = new ArrayList<String>();

}

@After

public void tearDown() {

emptyList = null;

}

@Test

public void testEmptyList() {

assertEquals("Empty list should have 0 elements",

0, emptyList.size());

}

}

Here the important plugin

mechanism is Java

annotations

62

17-214/514

63 of 63

Summary

  • Reuse and variation essential
    • Libraries and frameworks
  • Whitebox frameworks vs. blackbox frameworks
  • Design for reuse with domain analysis
    • Find common and variable parts
    • Write client applications to find common parts

63

17-214/514