Successfully reported this slideshow.
Upcoming SlideShare
×

# CRUFT! - Peter Kriens, President, aQute

207 views

Published on

OSGi World Congress 2005 - Developer Forum Day 2

Published in: Technology
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

• Be the first to like this

### CRUFT! - Peter Kriens, President, aQute

1. 1. Cruft! Peter Kriens, CEO,Peter Kriens, CEO, aQuteaQute
2. 2. CruftCruft!! •• cruftcruft is redundant, old or improperlyis redundant, old or improperly written code which needs to be fixed,written code which needs to be fixed, but tends to stick around.but tends to stick around.
3. 3. Why IsWhy Is CruftCruft Bad!Bad! •• More work to writeMore work to write •• Adds redundancyAdds redundancy •• More potential for errorsMore potential for errors •• Harder to read and understandHarder to read and understand •• Harder to extendHarder to extend •• Harder to optimizeHarder to optimize
4. 4. LowLow--CruftCruft LanguagesLanguages •• APLAPL –– PRIMES : (~PRIMES : (~RR∈∈RR••..××R)/RR)/R ←←11¡¡RR –– Maybe a trifle tooMaybe a trifle too condensecondense •• SmalltalkSmalltalk –– (Integer(Integer primesUpToprimesUpTo: 100): 100) maxmax –– Extremely lowExtremely low cruftcruft syntaxsyntax without becomingwithout becoming unreadableunreadable •• Compare this toCompare this to package primes; public class Primes { public static void main(String[] args) throws Exception { int max = 10000000; boolean[] isprime = new boolean[max + 1]; for (int i = 0; i <= max; i++) isprime[i] = true; isprime[0] = isprime[1] = false; int n = (int) Math.ceil(Math.sqrt(max)); for (int i = 0; i <= n; i++) { if (isprime[i]) for (int j = 2 * i; j <= max; j = j + i) isprime[j] = false; } int largest; for (largest = max; !isprime[largest]; largest--) ; // empty loop body System.out.println(largest); } }
5. 5. HighHigh CruftCruft LanguagesLanguages •• Java is a very verbose languageJava is a very verbose language –– Simple things require an amazing amount of codeSimple things require an amazing amount of code –– Type safe languages have this tendency. Sometimes oneType safe languages have this tendency. Sometimes one wonders if the type safety is needed to handle thewonders if the type safety is needed to handle the cruftcruft that itthat it causescauses …… •• OSGi adds additionalOSGi adds additional cruftcruft –– Service dependenciesService dependencies –– Bundle dependenciesBundle dependencies •• Using OSGi is very intrusive in the application codeUsing OSGi is very intrusive in the application code –– High learning thresholdHigh learning threshold –– Programmers are initially appalled when they have not yet seenProgrammers are initially appalled when they have not yet seen the advantagesthe advantages
6. 6. So What?So What? •• Lets analyze how muchLets analyze how much cruftcruft is added by creatingis added by creating an OSGi servicean OSGi service
7. 7. A Logging Echo ServiceA Logging Echo Service package aQute.opm.echo; public interface Echo { String echo(String msg); }
8. 8. Plain Old OSGiPlain Old OSGi packagepackage aQute.opm.echo.plainaQute.opm.echo.plain;; importimport java.utiljava.util.*;.*; import org.osgi.framework.*;import org.osgi.framework.*; importimport org.osgi.service.cmorg.osgi.service.cm.*;.*; importimport aQute.opm.echo.EchoaQute.opm.echo.Echo;; public class Activator implements BundleActivator,public class Activator implements BundleActivator, ManagedServiceManagedService {{ PlainEchoPlainEcho echo;echo; public voidpublic void start(BundleContextstart(BundleContext context) throws Exception {context) throws Exception { DictionaryDictionary map = newmap = new HashtableHashtable();(); map.put("service.pidmap.put("service.pid", "", "aQute.opm.echo.plainaQute.opm.echo.plain");"); echo = newecho = new PlainEcho(contextPlainEcho(context);); context.registerService(Echo.class.getNamecontext.registerService(Echo.class.getName(), echo, map );(), echo, map ); map.put("service.pidmap.put("service.pid", "", "aQute.opm.echo.plain.msaQute.opm.echo.plain.ms");"); context.registerService(ManagedService.class.getNamecontext.registerService(ManagedService.class.getName(), this, map );(), this, map ); }} public voidpublic void stop(BundleContextstop(BundleContext context) throws Exception {}context) throws Exception {} public voidpublic void updated(Dictionaryupdated(Dictionary map) throwsmap) throws ConfigurationExceptionConfigurationException {{ if ( map == null ) return;if ( map == null ) return; echo.toupperecho.toupper = "true" .= "true" .equals(map.get("toupperequals(map.get("toupper"));")); }}
9. 9. Plain Old OSGiPlain Old OSGi package aQute.opm.echo.plain; import java.util.*; import org.osgi.framework.*; import org.osgi.service.cm.*; import aQute.opm.echo.Echo; public class Activator implements BundleActivator, ManagedService { PlainEcho echo; public void start(BundleContext context) throws Exception { Dictionary map = new Hashtable(); map.put("service.pid", "aQute.opm.echo.plain"); echo = new PlainEcho(context); context.registerService(Echo.class.getName(), echo, map ); map.put("service.pid", "aQute.opm.echo.plain.ms"); context.registerService(ManagedService.class.getName(), this, map ); } public void stop(BundleContext context) throws Exception {} public void updated(Dictionary map) throws ConfigurationException { if ( map == null ) return; echo.toupper = "true" .equals(map.get("toupper")); }
10. 10. Now the Pay LoadNow the Pay Load packagepackage aQute.opm.echo.plainaQute.opm.echo.plain;; importimport org.osgi.framework.BundleContextorg.osgi.framework.BundleContext;; importimport org.osgi.service.log.LogServiceorg.osgi.service.log.LogService;; importimport org.osgi.util.tracker.ServiceTrackerorg.osgi.util.tracker.ServiceTracker;; importimport aQute.opm.echo.EchoaQute.opm.echo.Echo;; public classpublic class PlainEchoPlainEcho implements Echo {implements Echo { booleanboolean touppertoupper;; ServiceTrackerServiceTracker logTrackerlogTracker;; PlainEcho(BundleContextPlainEcho(BundleContext context) {context) { logTrackerlogTracker = new= new ServiceTracker(contextServiceTracker(context,, LogService.class.getNameLogService.class.getName(), null);(), null); }} public Stringpublic String echo(Stringecho(String msgmsg) {) { if (if (touppertoupper)) msgmsg == msg.toUpperCasemsg.toUpperCase();(); LogService log;LogService log; try {try { log = (LogService) logTracker.waitForService(10000);log = (LogService) logTracker.waitForService(10000); } catch (} catch (InterruptedExceptionInterruptedException e) { returne) { return msgmsg; }; } if (log != null)if (log != null) log.log(LogService.LOG_INFOlog.log(LogService.LOG_INFO,, msgmsg);); returnreturn msgmsg;; }} }}
11. 11. Now the Pay LoadNow the Pay Load package aQute.opm.echo.plain; import org.osgi.framework.BundleContext; import org.osgi.service.log.LogService; import org.osgi.util.tracker.ServiceTracker; import aQute.opm.echo.Echo; public class PlainEcho implements Echo { boolean toupper; ServiceTracker logTracker; PlainEcho(BundleContext context) { logTracker = new ServiceTracker(context, LogService.class.getName(), null); } public String echo(String msg) { if (toupper) msg = msg.toUpperCase(); LogService log; try { log = (LogService) logTracker.waitForService(10000); } catch (InterruptedException e) { return msg; } if (log != null) log.log(LogService.LOG_INFO, msg); return msg; } }
12. 12. Declarative Services?Declarative Services? •• In R4 we added Declarative Services for exactlyIn R4 we added Declarative Services for exactly this reasons. And Service Binder exists for somethis reasons. And Service Binder exists for some time. Are those not the answer?time. Are those not the answer? •• Lets tryLets try ……
13. 13. Echo With Declarative ServicesEcho With Declarative Services packagepackage aQute.opm.echo.declarativeaQute.opm.echo.declarative;; importimport org.osgi.service.component.ComponentContextorg.osgi.service.component.ComponentContext;; importimport org.osgi.service.log.LogServiceorg.osgi.service.log.LogService;; importimport aQute.opm.echo.EchoaQute.opm.echo.Echo;; public classpublic class DeclarativeComponentDeclarativeComponent implements Echo {implements Echo { booleanboolean touppertoupper;; ComponentContextComponentContext context;context; protected voidprotected void activate(ComponentContextactivate(ComponentContext context) {context) { this.contextthis.context = context;= context; }} public Stringpublic String echo(Stringecho(String msgmsg) {) { if (if (touppertoupper)) msgmsg == msg.toUpperCasemsg.toUpperCase();(); LogService log = (LogService)LogService log = (LogService) context.locateService("logcontext.locateService("log");"); log.log(LogService.LOG_INFOlog.log(LogService.LOG_INFO,, msgmsg);); returnreturn msgmsg;; }} }}
14. 14. Echo With Declarative ServicesEcho With Declarative Services package aQute.opm.echo.declarative; import org.osgi.service.component.ComponentContext; import org.osgi.service.log.LogService; import aQute.opm.echo.Echo; public class DeclarativeComponent implements Echo { boolean toupper; ComponentContext context; protected void activate(ComponentContext context) { this.context = context; } public String echo(String msg) { if (toupper) msg = msg.toUpperCase(); LogService log = (LogService) context.locateService("log"); log.log(LogService.LOG_INFO, msg); return msg; } }
15. 15. Oops, forgot the XMLOops, forgot the XML <?xml version="1.0" encoding="UTF<?xml version="1.0" encoding="UTF--8"?>8"?> <component<component name="name="aQute.opm.echo.declarativeaQute.opm.echo.declarative"" xmlnsxmlns="http://www.osgi.org/xmlns/scr/v1.0.0">="http://www.osgi.org/xmlns/scr/v1.0.0"> <implementation class="<implementation class="aQute.opm.echo.declarative.DeclarativeComponentaQute.opm.echo.declarative.DeclarativeComponent"/>"/> <service><service> <provide interface="<provide interface="aQute.opm.echo.EchoaQute.opm.echo.Echo"/>"/> </service></service> <reference name="log"<reference name="log" interface="interface="org.osgi.service.log.LogServiceorg.osgi.service.log.LogService"" />/> </component></component>
16. 16. Oops, forgot the XMLOops, forgot the XML <?xml version="1.0" encoding="UTF-8"?> <component name="aQute.opm.echo.declarative" xmlns="http://www.osgi.org/xmlns/scr/v1.0.0"> <implementation class="aQute.opm.echo.declarative.DeclarativeComponent"/> <service> <provide interface="aQute.opm.echo.Echo"/> </service> <reference name="log" interface="org.osgi.service.log.LogService" /> </component>
17. 17. Then On The Other SideThen On The Other Side •• Lets analyze the problemLets analyze the problem •• How would this example look like with only theHow would this example look like with only the JavaJava cruftcruft??
18. 18. Then On The Other SideThen On The Other Side packagepackage aQute.opm.echo.opmaQute.opm.echo.opm;; importimport org.osgi.service.log.LogServiceorg.osgi.service.log.LogService;; importimport aQute.opm.echo.EchoaQute.opm.echo.Echo;; public class Component implements Echo {public class Component implements Echo { private LogServiceprivate LogService log;log; booleanboolean toUppertoUpper;; public Stringpublic String echo(Stringecho(String message) {message) { if (if ( toUppertoUpper )) message =message = message.toUpperCasemessage.toUpperCase();(); log.log(LogService.LOG_INFOlog.log(LogService.LOG_INFO, message );, message ); return message;return message; }} }}
19. 19. What is Missing?What is Missing? •• What would a handler need to run this example?What would a handler need to run this example? –– The name of the classThe name of the class –– The service that must be registered for this component:The service that must be registered for this component: EchoEcho –– The dependency on the Log Service with the logThe dependency on the Log Service with the log variablevariable •• Lets design a manifest headerLets design a manifest header ……
20. 20. Manifest HeaderManifest Header ManifestManifest--Version: 1.0Version: 1.0 BundleBundle--Name:Name: aQute.opm.echo.opmaQute.opm.echo.opm BundleBundle--Activator:Activator: scr.ComponentRuntimescr.ComponentRuntime Component:Component: aQute.opm.echo.opm.ComponentaQute.opm.echo.opm.Component;; mandatory=log;mandatory=log; objectclassobjectclass==aQute.opm.echo.EchoaQute.opm.echo.Echo;; configconfig==touppertoupper \$(IMPORT\$(IMPORT--PACKAGE)PACKAGE) \$(EXPORT\$(EXPORT--PACKAGE)PACKAGE)
21. 21. Manifest HeaderManifest Header ManifestManifest--Version: 1.0Version: 1.0 BundleBundle--Name:Name: aQute.opm.echo.opmaQute.opm.echo.opm BundleBundle--Activator:Activator: scr.ComponentRuntime Component: aQute.opm.echo.opm.Component; mandatory=log; objectclass=aQute.opm.echo.Echo; config=toupper \$(IMPORT\$(IMPORT--PACKAGE)PACKAGE) \$(EXPORT\$(EXPORT--PACKAGE)PACKAGE)
22. 22. HooksHooks package aQute.opm.echo.opm; import org.osgi.service.log.LogService; import aQute.opm.echo.Echo; public class Component implements Echo { private LogService log; boolean toUpper; public String echo(String message) { if ( toUpper ) message = message.toUpperCase(); log.log(LogService.LOG_INFO, message ); return message; } } Manifest-Version: 1.0 Bundle-Name: aQute.opm.echo.opm Bundle-Activator: scr.ComponentRuntime Component: aQute.opm.echo.opm.Component; mandatory=log; objectclass=aQute.opm.echo.Echo; config=toupper \$(IMPORT-PACKAGE) \$(EXPORT-PACKAGE)
23. 23. The Component Handler StructureThe Component Handler Structure echoopm Get the manifest info Register service as a ServiceFactory Create service when needed Activator
24. 24. How Are the Dependencies Handled?How Are the Dependencies Handled? •• The Component uses the log instance variableThe Component uses the log instance variable without any concerns for dependencies orwithout any concerns for dependencies or initializationinitialization •• The handler only gets the name of the fields, notThe handler only gets the name of the fields, not the typesthe types •• The Handler should be careful not to set theThe Handler should be careful not to set the loglog field when it is never needed.field when it is never needed. –– Lazy initialization, do not consume services when notLazy initialization, do not consume services when not neededneeded
25. 25. Byte Code WeavingByte Code Weaving •• The handler can do its magic if it couldThe handler can do its magic if it could change/read the byte codes of the classchange/read the byte codes of the class –– Types of variables are defined in the byte codeTypes of variables are defined in the byte code –– References to dependents can be changed to aReferences to dependents can be changed to a callbackcallback •• The OPM prototype:The OPM prototype: –– Replaces all service references with its own object, aReplaces all service references with its own object, a CompenentDependencyCompenentDependency –– All references to the service are replaced with aAll references to the service are replaced with a callback to thecallback to the ComponentDependencyComponentDependency
26. 26. ImplementationImplementation •• The bundleThe bundle--activator is loaded from the OPM bundle.activator is loaded from the OPM bundle. –– Reads manifestReads manifest –– Analyzes Component class for missing informationAnalyzes Component class for missing information –– Starts dependency checkingStarts dependency checking –– Activates Components when dependencies are metActivates Components when dependencies are met •• The Component class is analyzed and rewritten using aThe Component class is analyzed and rewritten using a custom class loadercustom class loader –– Gets the bytes from the class loader of the application bundleGets the bytes from the class loader of the application bundle –– Uses ASM fromUses ASM from ObjectwebObjectweb •• If the Framework standardized the custom hook for theIf the Framework standardized the custom hook for the Declarative Service, then OPM could use it as wellDeclarative Service, then OPM could use it as well –– No OPM Activator would then be necessaryNo OPM Activator would then be necessary