cruft! peter kriens, ceo, aqute cruft! cruft is redundant, old or improperly written code which...

32

Upload: leah-cantrell

Post on 27-Mar-2015

222 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is
Page 2: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Cruft!

Peter Kriens, CEO, aQutePeter Kriens, CEO, aQute

Page 3: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Cruft!Cruft!

• cruftcruft is redundant, old or improperly is 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.

Page 4: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Why Is Cruft Bad!Why Is Cruft 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

Page 5: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Low-Cruft LanguagesLow-Cruft Languages

• APLAPL– PRIMES : (~PRIMES : (~RRRR..×R)/R×R)/R1¡1¡RR

– Maybe a trifle too Maybe a trifle too condensecondense

• SmalltalkSmalltalk– (Integer primesUpTo: 100) max(Integer primesUpTo: 100) max

– Extremely low cruft syntax Extremely low cruft syntax without becoming without becoming unreadableunreadable

• Compare this toCompare this topackage 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); }}

Page 6: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

High Cruft LanguagesHigh Cruft Languages

• 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 one Type safe languages have this tendency. Sometimes one

wonders if the type safety is needed to handle the cruft that it wonders if the type safety is needed to handle the cruft that it causes …causes …

• OSGi adds additional cruftOSGi adds additional cruft– 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 seen Programmers are initially appalled when they have not yet seen

the advantagesthe advantages

Page 7: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

So What?So What?

• Lets analyze how much cruft is added by creating Lets analyze how much cruft is added by creating an OSGi servicean OSGi service

Page 8: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

A Logging Echo ServiceA Logging Echo Service

package aQute.opm.echo;

public interface Echo {

String echo(String msg);

}

Page 9: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Plain Old OSGiPlain Old OSGi

package aQute.opm.echo.plain;package aQute.opm.echo.plain;import java.util.*;import java.util.*;import org.osgi.framework.*;import org.osgi.framework.*;import org.osgi.service.cm.*;import org.osgi.service.cm.*;import aQute.opm.echo.Echo;import aQute.opm.echo.Echo;

public class Activator implements BundleActivator, ManagedService {public class Activator implements BundleActivator, ManagedService { PlainEchoPlainEcho echo;echo; public void start(BundleContext context) throws Exception {public void start(BundleContext context) throws Exception { DictionaryDictionary map = new Hashtable();map = new Hashtable(); map.put("service.pid", "aQute.opm.echo.plain");map.put("service.pid", "aQute.opm.echo.plain"); echo = new PlainEcho(context);echo = new PlainEcho(context); context.registerService(Echo.class.getName(), echo, map );context.registerService(Echo.class.getName(), echo, map ); map.put("service.pid", "aQute.opm.echo.plain.ms");map.put("service.pid", "aQute.opm.echo.plain.ms"); context.registerService(ManagedService.class.getName(), this, map );context.registerService(ManagedService.class.getName(), this, map );}}

public void stop(BundleContext context) throws Exception {}public void stop(BundleContext context) throws Exception {}

public void updated(Dictionary map) throws ConfigurationException {public void updated(Dictionary map) throws ConfigurationException { if ( map == null ) return;if ( map == null ) return; echo.toupper = "true" .equals(map.get("toupper"));echo.toupper = "true" .equals(map.get("toupper"));}}

Page 10: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

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"));}

Page 11: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Now the Pay LoadNow the Pay Load

package aQute.opm.echo.plain;package aQute.opm.echo.plain;

import org.osgi.framework.BundleContext;import org.osgi.framework.BundleContext;import org.osgi.service.log.LogService;import org.osgi.service.log.LogService;import org.osgi.util.tracker.ServiceTracker;import org.osgi.util.tracker.ServiceTracker;

import aQute.opm.echo.Echo;import aQute.opm.echo.Echo;

public class PlainEcho implements Echo {public class PlainEcho implements Echo { booleanboolean toupper;toupper; ServiceTrackerServiceTracker logTracker;logTracker;

PlainEcho(BundleContext context) {PlainEcho(BundleContext context) { logTracker = new ServiceTracker(context, LogService.class.getName(), null);logTracker = new ServiceTracker(context, LogService.class.getName(), null); }}

public String echo(String msg) {public String echo(String msg) { if (toupper)if (toupper) msg = msg.toUpperCase();msg = msg.toUpperCase(); LogService log;LogService log; try {try { log = (LogService) logTracker.waitForService(10000);log = (LogService) logTracker.waitForService(10000); } catch (InterruptedException e) { return msg; }} catch (InterruptedException e) { return msg; } if (log != null) log.log(LogService.LOG_INFO, msg);if (log != null) log.log(LogService.LOG_INFO, msg); return msg;return msg; }}}}

Page 12: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

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; }}

Page 13: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Declarative Services?Declarative Services?

• In R4 we added Declarative Services for exactly In R4 we added Declarative Services for exactly this reasons. And Service Binder exists for some this reasons. And Service Binder exists for some time. Are those not the answer?time. Are those not the answer?

• Lets try …Lets try …

Page 14: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Echo With Declarative ServicesEcho With Declarative Services

package aQute.opm.echo.declarative;package aQute.opm.echo.declarative;

import org.osgi.service.component.ComponentContext;import org.osgi.service.component.ComponentContext;import org.osgi.service.log.LogService;import org.osgi.service.log.LogService;

import aQute.opm.echo.Echo;import aQute.opm.echo.Echo;

public class DeclarativeComponent implements Echo {public class DeclarativeComponent implements Echo {booleanboolean toupper;toupper;ComponentContextComponentContext context;context;

protected void activate(ComponentContext context) {protected void activate(ComponentContext context) {this.context = context;this.context = context;

}}

public String echo(String msg) {public String echo(String msg) {if (toupper)if (toupper)

msg = msg.toUpperCase();msg = msg.toUpperCase();LogService log = (LogService) context.locateService("log");LogService log = (LogService) context.locateService("log");log.log(LogService.LOG_INFO, msg);log.log(LogService.LOG_INFO, msg);return msg;return msg;

}}

}}

Page 15: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

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;

}

}

Page 16: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Oops, forgot the XMLOops, forgot the XML

<?xml version="1.0" encoding="UTF-8"?><?xml version="1.0" encoding="UTF-8"?><component <component

name="aQute.opm.echo.declarative"name="aQute.opm.echo.declarative"xmlns="http://www.osgi.org/xmlns/scr/v1.0.0">xmlns="http://www.osgi.org/xmlns/scr/v1.0.0"><implementation class="aQute.opm.echo.declarative.DeclarativeComponent"/><implementation class="aQute.opm.echo.declarative.DeclarativeComponent"/><service><service>

<provide interface="aQute.opm.echo.Echo"/><provide interface="aQute.opm.echo.Echo"/></service></service><reference name="log"<reference name="log"

interface="org.osgi.service.log.LogService"interface="org.osgi.service.log.LogService"/>/>

</component></component>

Page 17: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

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>

Page 18: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Then On The Other SideThen On The Other Side

• Lets analyze the problemLets analyze the problem

• How would this example look like with only the How would this example look like with only the Java cruft?Java cruft?

Page 19: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Then On The Other SideThen On The Other Side

package aQute.opm.echo.opm;package aQute.opm.echo.opm;

import org.osgi.service.log.LogService;import org.osgi.service.log.LogService;

import aQute.opm.echo.Echo;import aQute.opm.echo.Echo;

public class Component implements Echo {public class Component implements Echo {private LogServiceprivate LogService log;log;boolean toUpper;boolean toUpper;

public String echo(String message) {public String echo(String message) {if ( toUpper )if ( toUpper )

message = message.toUpperCase();message = message.toUpperCase();log.log(LogService.LOG_INFO, message );log.log(LogService.LOG_INFO, message );return message;return message;

}}}}

Page 20: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

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 log The dependency on the Log Service with the log

variablevariable

• Lets design a manifest header …Lets design a manifest header …

Page 21: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Manifest HeaderManifest Header

Manifest-Version: 1.0Manifest-Version: 1.0Bundle-Name: aQute.opm.echo.opmBundle-Name: aQute.opm.echo.opmBundle-Activator: Bundle-Activator: scr.ComponentRuntimescr.ComponentRuntimeComponent: aQute.opm.echo.opm.Component;Component: aQute.opm.echo.opm.Component; mandatory=log;mandatory=log; objectclass=aQute.opm.echo.Echo;objectclass=aQute.opm.echo.Echo; config=toupperconfig=toupper$(IMPORT-PACKAGE)$(IMPORT-PACKAGE)$(EXPORT-PACKAGE)$(EXPORT-PACKAGE)

Page 22: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Manifest HeaderManifest Header

Manifest-Version: 1.0Manifest-Version: 1.0Bundle-Name: aQute.opm.echo.opmBundle-Name: aQute.opm.echo.opmBundle-Activator: Bundle-Activator: scr.ComponentRuntimeComponent: aQute.opm.echo.opm.Component; mandatory=log; objectclass=aQute.opm.echo.Echo; config=toupper$(IMPORT-PACKAGE)$(IMPORT-PACKAGE)$(EXPORT-PACKAGE)$(EXPORT-PACKAGE)

Page 23: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

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.0Bundle-Name: aQute.opm.echo.opmBundle-Activator: scr.ComponentRuntimeComponent: aQute.opm.echo.opm.Component; mandatory=log; objectclass=aQute.opm.echo.Echo; config=toupper$(IMPORT-PACKAGE)$(EXPORT-PACKAGE)

Page 24: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

The Component Handler StructureThe Component Handler Structure

echoopm

Get the manifest info

Register service as a ServiceFactory

Create service when needed

Activator

Page 25: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

How Are the Dependencies Handled?How Are the Dependencies Handled?

• The Component uses the log instance variable The Component uses the log instance variable without any concerns for dependencies or without any concerns for dependencies or initializationinitialization

• The handler only gets the name of the fields, not The handler only gets the name of the fields, not the typesthe types

• The Handler should be careful not to set the The 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 not Lazy initialization, do not consume services when not neededneeded

Page 26: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Byte Code WeavingByte Code Weaving

• The handler can do its magic if it could The 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 a References to dependents can be changed to a

callbackcallback

• The OPM prototype:The OPM prototype:– Replaces all service references with its own object, a Replaces all service references with its own object, a

CompenentDependencyCompenentDependency– All references to the service are replaced with a All references to the service are replaced with a

callback to the ComponentDependencycallback to the ComponentDependency

Page 27: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

ImplementationImplementation

• The bundle-activator is loaded from the OPM bundle.The 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 a The Component class is analyzed and rewritten using a custom class loader custom 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 from ObjectwebUses ASM from Objectweb

• If the Framework standardized the custom hook for the If 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

Page 28: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

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}

Page 29: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

IssuesIssues

• PerformancePerformance– Access to services is slightly slowerAccess to services is slightly slower

• More memory usageMore memory usage– Tracking the dependencies requires a number of Tracking 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 byte Some developers do not like changes in their byte

codescodes

• It is uncommon for developer that their private It is uncommon for developer that their private variables change from the outsidevariables change from the outside

Page 30: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

Work In ProgressWork In Progress

• Configuration DataConfiguration Data– Instance variables can be declared to come from configuration Instance variables can be declared to come from configuration

datadata– Automatic type coercionAutomatic type coercion

• Use of Managed Service Factories to drive the 0..n Use of Managed Service Factories to drive the 0..n component creationscomponent creations

– Very useful for services that can be instantiated multiple times Very 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 syntax Use of standard AOP syntax • Use implemented interfaces as servicesUse implemented interfaces as services• Big trick is to keep it simple …Big trick is to keep it simple …

Page 31: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is

ConclusionConclusion

• The OPM uses a very specific form of byte code The OPM uses a very specific form of byte code weaving that is popularized by Aspect Oriented weaving that is popularized by Aspect Oriented Programming (AOP)Programming (AOP)

• AOP turns out to be extremely useful to remove AOP turns out to be extremely useful to remove cruftcruft

• The OPM prototype shows that it is possible to The OPM prototype shows that it is possible to remove all OSGi related aspects from code that remove 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

Page 32: Cruft! Peter Kriens, CEO, aQute Cruft! cruft is redundant, old or improperly written code which needs to be fixed, but tends to stick around.cruft is