Introduction to Component Models and Technologies • Why do we need them ? • What do they minimally do ? •How do they actually do it ? Review: Component Models and Component Frameworks Component Component Component Component platform (component framework) Middleware Operating System Hardware Platform Services: allow components written according to the model to communicate; locating, linking, replacing components Horizontal Services: application-independent services used by different components. Concurrency, security, transaction management, Resource management Component technologies • Component technology = component model + component framework • Different component models available: – Old and new – Industrial or research – General-purpose or specialized for different domains – Having different concepts for components – Providing a larger or smaller set of platform services • Examples: – Java Beans, EJB, COM, DCOM, .NET Components, CCM, OSGI, Spring, PicoContainer, Fractal, OpenCOM, Autosar, KOALA, PECOS, … Introduction goals • Motivation – Why do we need them ? – What is the minimum they must do ? • Basic principles – How do they actually do it ? • Bibliography: Martin Fowler: Inversion of Control Containers and the Dependency Injection Pattern, http://www.martinfowler.com/articles/injection.html • The Basic Goals of CBD • Assemble a system out of existing (third-party) components • Update a system by adding / replacing components • Component: – Is a unit of deployment – Is handled as it is (a blackbox) Example 1 • A simple text editor can be composed with a spell checker for English language or with a spell checker for Romanian language SpellChecker1 TextEditor SpellChecker2 Example 1 • The Component Diagram shows a simple hierarchical composition Example 2 • From: Martin Fowler: Inversion of Control Containers and the Dependency Injection Pattern MovieFinder1 MovieLister MovieFinder2 Example 2 • A MovieLister is able to list movies with certain characteristics after being provided an exhaustive list of movies by a MovieFinder • MovieFinder is an interface; • There could be several different MovieFinderImpl components: one implementation finds movies by reading a text file, one finds movies from a relational database, one finds movies crawling the web for movie advertisings, etc. A naive solution design public interface MovieFinder { List findAll(); } public class MovieLister { private MovieFinder finder; This is good public Movie[] moviesDirectedBy(String arg) { List allMovies = finder.findAll(); for (Iterator it = allMovies.iterator(); it.hasNext();) { Movie movie = (Movie) it.next(); if (!movie.getDirector().equals(arg)) it.remove(); } return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]); } } BUT the MovieLister will still need a MovieFinderImplementation ! public interface MovieFinder { List findAll(); } public class MovieLister { private MovieFinder finder; public Movie[] moviesDirectedBy(String arg) { List allMovies = finder.findAll(); for (Iterator it = allMovies.iterator(); it.hasNext();) { Movie movie = (Movie) it.next(); if (!movie.getDirector().equals(arg)) it.remove(); } return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]); } public MovieLister() { finder = new MySpecialMovieFinderImplem(); } } This is BAD !! The goal: loosely coupled components • MovieLister should work with any MovieFinderImplementation • MovieLister does not need to know the particular type of finder implementation it is using • The good solution: eliminate all lines of code such as: • MovieFinder f = new MyParticularMovieFinderImpl(); – A component should NEVER create (instantiate) its dependencies • The solution is called “Inversion of Control” – In this context, IoC means that a component does not create (instantiate) its dependencies but has someone else creating them for it The concept of “Inversion of Control” • The general definition: – All application frameworks make use of a design pattern known as “inversion of control” • It occurs whenever we define code that will be called by the framework to handle application specific behavior • This is what distinguishes a framework from a library The concept of “Inversion of Control” • In the context of components: – The application independently defines a set of components and their dependencies and the component framework (called container) uses this information to • wire the components together at run-time • call its code at specific times in the life cycle Inversion of Control • Inversion of Control can be achieved through several patterns: – Dependency Injection – Service Locator Dependency Injection An Assembler instantiates concrete implementations and “injects” them into the component that needs them Forms of Dependency Injection • Constructor Injection – MovieLister has a constructor that will get the MovieFinderImplementation • Setter Injection – MovieLister has a setter method that will get the MovieFinderImplementation • Interface Injection – An interface InjectFinder, with method injectFinder, defined by the provider of the MovieFinder interface – MovieLister (and any class that wants to use a MovieFinder) needs to implement this interface Component Containers • What has the Dependency Injector pattern to do with component frameworks ? • The “Assembler” component of the Dependency Injection pattern is called a “Component Container” and is part of the component framework – The assembler (Container) is generic (for any application), thus it: • Requires that components follow a certain convention (constructor, setter, injector interfaces) • Requires to be told (by code or configuration files) which implementation to associate with which interface Using Component Containers 1) Take a set of components (concrete classes + interfaces) • 2) 3) they have to implement constructors, setters or interfaces for dependency injection – according to the convention required by the component framework Add configuration info in form of: • Configuration metadata (config files) • Configuration code Add client code to use the container Examples • Component Containers are used in many component frameworks: – “Lightweight” IoC Containers – Complex component frameworks, that provide also other features beyond IoC Containers • Examples: • • • • • • • PicoContainer Spring Unity Guice EJB CCM OSGI with DS Example: Constructor Injection with PicoContainer (1) Including Constructors class MovieLister... public MovieLister(MovieFinder finder) { this.finder = finder; } class ColonMovieFinder... public ColonMovieFinder(String filename) { this.filename = filename; } Each class declares constructors that include everything it needs injected Example: Constructor Injection with PicoContainer (2) Describing the configuration private MutablePicoContainer configureContainer() { MutablePicoContainer pico = new DefaultPicoContainer(); Parameter[] finderParams = {new ConstantParameter("movies1.txt")}; pico.registerComponentImplementation(MovieFinder.class, ColonMovieFinder.class, finderParams); pico.registerComponentImplementation(MovieLister.class); return pico; } The pico container needs to This kind of configuration information could be told which implementation come as well from configuration files. Some class to associate with each component frameworks support it to interface, andreading which string from config inject files into the finder Example: Constructor Injection with PicoContainer (3) Using the composed system public void testWithPico() { MutablePicoContainer pico = configureContainer(); MovieLister lister = (MovieLister) pico.getComponentInstance(MovieLister.class); Movie[] movies = lister.moviesDirectedBy("Sergio Leone"); assertEquals("Once Upon a Time in the West", movies[0].getTitle()); } Example: Setter Injection with Spring (1) Defining setters class MovieLister... public void setFinder(MovieFinder finder) { this.finder = finder; } class ColonMovieFinder... public void setFilename(String filename) { this.filename = filename; } Each class defines setters that include everything it needs injected Example: Setter Injection with Spring (2) Describing the configuration <beans> <bean id="MovieLister" class="spring.MovieLister"> <property name="finder"> <ref local="MovieFinder"/> </property> </bean> <bean id="MovieFinder" class="spring.ColonMovieFinder"> <property name="filename"> <value>movies1.txt</value> </property> </bean> </beans> Example: Setter Injection with Spring (3) Describing the configuration public void testWithSpring() throws Exception { ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml"); MovieLister lister = (MovieLister) ctx.getBean("MovieLister"); Movie[] movies = lister.moviesDirectedBy("Sergio Leone"); assertEquals("Once Upon a Time in the West", movies[0].getTitle()); } Inversion of Control • Inversion of Control can be achieved through several patterns: – Dependency Injection – Service Locator Service Locator A Service Locator knows how to get hold of all of the services that an application might need. Example: Service Location with OSGI (1) Registering the service public class BasicMovieFinderActivator implements BundleActivator { private ServiceRegistration registration; public void start(BundleContext context) { MovieFinder finder = new BasicMovieFinderImpl(); registration = context.registerService( MovieFinder.class.getName(), finder, null); …. } This Service Locator is a Dynamic one (it allows to stash any service you need into it and make the choices at runtime) Example: Service Location with OSGI (2) Retrieving the service public class MovieListerActivator implements BundleActivator { private ServiceTracker finderTracker; public void start(BundleContext context) throws Exception { … finderTracker = new ServiceTracker(context, MovieFinder.class.getName(), null); finderTracker.open(); MovieFinder finder = (MovieFinder) finderTrack.getService(); …. } Comparison: Service Locator vs Dependency Injection • Both provide decoupling (keep application code dependent only on interfaces, not on implementations) • Other criteria: – How explicit are the dependencies ? – How “intrusive” is the approach into the application code ? – Dynamic dependencies are possible ? Comparison: (1) Service Locator vs Dependency Injection • “Intrusive” into application code: – With service locator, the application component explicitly asks the locator for its dependency • Every component has a dependency to the locator • This is “intrusive” into the component development process (such components cannot be used without the framework) – With dependency injection, the application component does not have to ask anything, its dependencies just appear injected • Less intrusive, such components could be used without the framework Comparison: (2) Service Locator vs Dependency Injection • Explicit dependencies: – With service locator you have to search the source code for calls to the locator. – With dependency injection you can just look at the injection mechanism, such as the constructor, and see the dependencies. Comparison: (3) Service Locator vs Dependency Injection • Dynamic dependencies: – With dependency injection you don't have a dependency from a component to the injector, the component cannot obtain further services from the injector once it's been configured. – With service locator a component can locate new services at any time or replace/update them . Conclusion • Component frameworks must support the assembly of independent components into applications at deployment time or even runtime – lightweight IoC containers at least • Component frameworks may support different additional aspects: – Component lifecycle support – Hierarchical components – Concurrency, distribution, transactions, …