Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Cruft!
Peter Kriens, CEO,Peter Kriens, CEO, aQuteaQute
CruftCruft!!
•• cruftcruft is redundant, old or improperlyis redundant, old or improperly
written code which needs to be f...
Why IsWhy Is CruftCruft Bad!Bad!
•• More work to writeMore work to write
•• Adds redundancyAdds redundancy
•• More potenti...
LowLow--CruftCruft LanguagesLanguages
•• APLAPL
–– PRIMES : (~PRIMES : (~RR∈∈RR••..××R)/RR)/R ←←11¡¡RR
–– Maybe a trifle t...
HighHigh CruftCruft LanguagesLanguages
•• Java is a very verbose languageJava is a very verbose language
–– Simple things ...
So What?So What?
•• Lets analyze how muchLets analyze how much cruftcruft is added by creatingis added by creating
an OSGi...
A Logging Echo ServiceA Logging Echo Service
package aQute.opm.echo;
public interface Echo {
String echo(String msg);
}
Plain Old OSGiPlain Old OSGi
packagepackage aQute.opm.echo.plainaQute.opm.echo.plain;;
importimport java.utiljava.util.*;....
Plain Old OSGiPlain Old OSGi
package aQute.opm.echo.plain;
import java.util.*;
import org.osgi.framework.*;
import org.osg...
Now the Pay LoadNow the Pay Load
packagepackage aQute.opm.echo.plainaQute.opm.echo.plain;;
importimport org.osgi.framework...
Now the Pay LoadNow the Pay Load
package aQute.opm.echo.plain;
import org.osgi.framework.BundleContext;
import org.osgi.se...
Declarative Services?Declarative Services?
•• In R4 we added Declarative Services for exactlyIn R4 we added Declarative Se...
Echo With Declarative ServicesEcho With Declarative Services
packagepackage aQute.opm.echo.declarativeaQute.opm.echo.decla...
Echo With Declarative ServicesEcho With Declarative Services
package aQute.opm.echo.declarative;
import org.osgi.service.c...
Oops, forgot the XMLOops, forgot the XML
<?xml version="1.0" encoding="UTF<?xml version="1.0" encoding="UTF--8"?>8"?>
<com...
Oops, forgot the XMLOops, forgot the XML
<?xml version="1.0" encoding="UTF-8"?>
<component
name="aQute.opm.echo.declarativ...
Then On The Other SideThen On The Other Side
•• Lets analyze the problemLets analyze the problem
•• How would this example...
Then On The Other SideThen On The Other Side
packagepackage aQute.opm.echo.opmaQute.opm.echo.opm;;
importimport org.osgi.s...
What is Missing?What is Missing?
•• What would a handler need to run this example?What would a handler need to run this ex...
Manifest HeaderManifest Header
ManifestManifest--Version: 1.0Version: 1.0
BundleBundle--Name:Name: aQute.opm.echo.opmaQute...
Manifest HeaderManifest Header
ManifestManifest--Version: 1.0Version: 1.0
BundleBundle--Name:Name: aQute.opm.echo.opmaQute...
HooksHooks
package aQute.opm.echo.opm;
import org.osgi.service.log.LogService;
import aQute.opm.echo.Echo;
public class Co...
The Component Handler StructureThe Component Handler Structure
echoopm
Get the manifest info
Register service as a Service...
How Are the Dependencies Handled?How Are the Dependencies Handled?
•• The Component uses the log instance variableThe Comp...
Byte Code WeavingByte Code Weaving
•• The handler can do its magic if it couldThe handler can do its magic if it could
cha...
ImplementationImplementation
•• The bundleThe bundle--activator is loaded from the OPM bundle.activator is loaded from the...
Automatic Weaving Under the CoverAutomatic Weaving Under the Cover
public class Component implements Echo{
private LogServ...
IssuesIssues
•• PerformancePerformance
–– Access to services is slightly slowerAccess to services is slightly slower
•• Mo...
Work In ProgressWork In Progress
•• Configuration DataConfiguration Data
–– Instance variables can be declared to come fro...
ConclusionConclusion
•• The OPM uses a very specific form of byte codeThe OPM uses a very specific form of byte code
weavi...
CRUFT! - Peter Kriens, President, aQute
CRUFT! - Peter Kriens, President, aQute
Upcoming SlideShare
Loading in …5
×

CRUFT! - Peter Kriens, President, aQute

207 views

Published on

OSGi World Congress 2005 - Developer Forum Day 2

Published in: Technology
  • 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
  27. 27. Automatic Weaving Under the CoverAutomatic Weaving Under the Cover public class Component implements Echo{ private LogService log; boolean toUpper; public Component(); Code: 0: aload_0 1: invokespecial 4: return public String echo(String); Code: 0: aload_0 1: getfield #toupper 4: ifeq 12 7: aload_1 8: invokevirtual #toUpperCase() 11: astore_1 12: aload_0 13: getfield #log 16: iconst_3 17: aload_1 18: invokeinterface #log() 23: aload_1 24: areturn } public class Component implements Echo{ private ComponentDependency log; boolean toUpper; public Component(); Code: 0: aload_0 1: invokespecial 4: return public String echo(String); Code: 0: aload_0 1: getfield #toupper 4: ifeq 12 7: aload_1 8: invokevirtual #toUpperCase() 11: astore_1 12: aload_0 13: getfield #log 16: invokevirtual #get 19: checkcast #LogService 22: iconst_3 23: aload_1 24: invokeinterface #log() 29: aload_1 30: areturn }
  28. 28. IssuesIssues •• PerformancePerformance –– Access to services is slightly slowerAccess to services is slightly slower •• More memory usageMore memory usage –– Tracking the dependencies requires a number ofTracking the dependencies requires a number of objects per service dependencyobjects per service dependency •• Change in byte codeChange in byte code –– Debuggers, though so far it looks okDebuggers, though so far it looks ok –– Some developers do not like changes in their byteSome developers do not like changes in their byte codescodes •• It is uncommon for developer that their privateIt is uncommon for developer that their private variables change from the outsidevariables change from the outside
  29. 29. Work In ProgressWork In Progress •• Configuration DataConfiguration Data –– Instance variables can be declared to come from configurationInstance variables can be declared to come from configuration datadata –– Automatic type coercionAutomatic type coercion •• Use of Managed Service Factories to drive the 0..nUse of Managed Service Factories to drive the 0..n component creationscomponent creations –– Very useful for services that can be instantiated multiple timesVery useful for services that can be instantiated multiple times with different configurationswith different configurations •• Use of Java annotations instead of manifest headerUse of Java annotations instead of manifest header •• Preprocessing during developmentPreprocessing during development •• Use of standard AOP syntaxUse of standard AOP syntax •• Use implemented interfaces as servicesUse implemented interfaces as services •• Big trick is to keep it simpleBig trick is to keep it simple ……
  30. 30. ConclusionConclusion •• The OPM uses a very specific form of byte codeThe OPM uses a very specific form of byte code weaving that is popularized by Aspect Orientedweaving that is popularized by Aspect Oriented Programming (AOP)Programming (AOP) •• AOP turns out to be extremely useful to removeAOP turns out to be extremely useful to remove cruftcruft •• The OPM prototype shows that it is possible toThe OPM prototype shows that it is possible to remove all OSGi related aspects from code thatremove all OSGi related aspects from code that runs on an OSGi Service Platformruns on an OSGi Service Platform –– Without losing any of the dynamicsWithout losing any of the dynamics

×