# HG changeset patch # User Jaroslav Tulach # Date 1231619362 -3600 # Node ID 77b6002451c4628da049ca4b97b8c5528676f7e2 # Parent fb84830aacc2eb0b4f1e62d40e493116252958b5 Initial version of sample to explain 'code injection' diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/build.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/build.xml Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,74 @@ + + + + + + + + + + + Builds, tests, and runs the project codeinjection. + + + diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/manifest.mf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/manifest.mf Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/nbproject/build-impl.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/nbproject/build-impl.xml Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/nbproject/genfiles.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/nbproject/genfiles.properties Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,8 @@ +build.xml.data.CRC32=4a8b5abf +build.xml.script.CRC32=83b773e3 +build.xml.stylesheet.CRC32=958a1d3e +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=4a8b5abf +nbproject/build-impl.xml.script.CRC32=87b63499 +nbproject/build-impl.xml.stylesheet.CRC32=18b47a54 diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/nbproject/project.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/nbproject/project.properties Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,65 @@ +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/codeinjection.jar +dist.javadoc.dir=${dist.dir}/javadoc +excludes= +file.reference.junit-4.4.jar=../libs/dist/junit-4.4.jar +file.reference.org-netbeans-insane.jar=../libs/dist/org-netbeans-insane.jar +file.reference.org-netbeans-modules-nbjunit.jar=../libs/dist/org-netbeans-modules-nbjunit.jar +includes=** +jar.compress=false +javac.classpath= +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${file.reference.junit-4.4.jar}:\ + ${file.reference.org-netbeans-insane.jar}:\ + ${file.reference.org-netbeans-modules-nbjunit.jar} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=org.apidesign.codeinjection.Main +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/nbproject/project.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/nbproject/project.xml Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,16 @@ + + + org.netbeans.modules.java.j2seproject + + + codeinjection + 1.6.5 + + + + + + + + + diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/src/org/apidesign/codeinjection/CountDown.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/src/org/apidesign/codeinjection/CountDown.java Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,27 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.apidesign.codeinjection; + +/** API class that can counts a count down. + * + * @author Jaroslav Tulach + * @since 1.0 + */ +// BEGIN: codeinjection.CountDown +public abstract class CountDown { + CountDown() { + } + + public static CountDown create(int initial) { + return new CountDownImplV1(initial); + } + + /** Decrements the counter */ + public abstract void down(); + /** @return true if the counter is 0 or less */ + public abstract boolean isDown(); +} +// END: codeinjection.CountDown diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/src/org/apidesign/codeinjection/CountDownImplV1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/src/org/apidesign/codeinjection/CountDownImplV1.java Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,29 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.apidesign.codeinjection; + +/** The implementation of {@link CountDown} as of version 1.0. + * The {@link #down()} method always decrements by one. + * + * @author Jaroslav Tulach + * @since 1.0 + */ +final class CountDownImplV1 extends CountDown { + CountDownImplV1(int initial) { + this.cnt = initial; + } + +// BEGIN: codeinjection.v1 + private int cnt; + public void down() { + cnt--; + } + + public boolean isDown() { + return cnt <= 0; + } +// END: codeinjection.v1 +} diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/src/org/apidesign/codeinjection/CountDownImplV2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/src/org/apidesign/codeinjection/CountDownImplV2.java Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,44 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.apidesign.codeinjection; + +import java.util.Iterator; +import java.util.ServiceLoader; +import org.apidesign.codeinjection.spi.CountDownExtender; + +/** Second version to {@link CountDownImplV1} - imagine someone wants to + * reimplement {@link #down()} method to decrement by two not just by one. + * You do not like that idea at all, but you do not want to prevent such + * behaviour. You just do not want to maintain such bloody code. What can + * you do? You need to allow code injection via the + * {@link CountDownExtender} class! + * + * @author Jaroslav Tulach + */ +final class CountDownImplV2 extends CountDown { + private int cnt; + + CountDownImplV2(int initial) { + this.cnt = initial; + } + +// BEGIN: codeinjection.v2 + public void down() { + Iterator it = ServiceLoader.load(CountDownExtender.class).iterator(); + if (it.hasNext()) { + // injected behaviour + cnt = it.next().decrement(cnt); + } else { + // common behaviour of 1.0 version + cnt--; + } + } + + public boolean isDown() { + return cnt <= 0; + } +// END: codeinjection.v2 +} diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/src/org/apidesign/codeinjection/spi/CountDownExtender.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/src/org/apidesign/codeinjection/spi/CountDownExtender.java Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,17 @@ +package org.apidesign.codeinjection.spi; + +/** Allows to define meaning of "--" + * + * @author Jaroslav Tulach + * @since 2.0 + */ +// BEGIN: codeinjection.slot +public interface CountDownExtender { + /** Allows providers to specify that it means to "decrement" a value. + * + * @param value previous value + * @return result of "--" operation in interpretation of this extender + */ + public int decrement(int value); +} +// END: codeinjection.slot diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/test/org/apidesign/codeinjection/Version10Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/test/org/apidesign/codeinjection/Version10Test.java Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,34 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.apidesign.codeinjection; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** Final count down test. + * + * @author Jaroslav Tulach + */ +public class Version10Test { + + public Version10Test() { + } + + /** creates version 1.0 */ + private static CountDown create(int value) { + return new CountDownImplV1(value); + } + + @Test + public void testDecrementFourTimes() { + CountDown counter = create(4); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertTrue("Down now", counter.isDown()); + } +} \ No newline at end of file diff -r fb84830aacc2 -r 77b6002451c4 samples/codeinjection/test/org/apidesign/codeinjection/Version20Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/codeinjection/test/org/apidesign/codeinjection/Version20Test.java Sat Jan 10 21:29:22 2009 +0100 @@ -0,0 +1,52 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.apidesign.codeinjection; + +import org.apidesign.codeinjection.spi.CountDownExtender; +import org.junit.Test; +import org.netbeans.junit.MockServices; +import static org.junit.Assert.*; + +/** Final count down test. + * + * @author Jaroslav Tulach + */ +public class Version20Test { + + public Version20Test() { + } + + /** creates version 2.0 */ + private static CountDown create(int value) { + return new CountDownImplV2(value); + } + + @Test + public void testDecrementFourTimes() { + MockServices.setServices(); + CountDown counter = create(4); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertTrue("Down now", counter.isDown()); + } + + @Test + public void testDecrementTwoTimesEnough() { + MockServices.setServices(DecrementByTwo.class); + CountDown counter = create(4); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertFalse("Not down yet", counter.isDown()); counter.down(); + assertTrue("Two Down is enough", counter.isDown()); + } + + public static final class DecrementByTwo implements CountDownExtender { + public int decrement(int value) { + return value - 2; + } + } +} \ No newline at end of file