Grape (The Groovy Adaptable Packaging Engine or Groovy Advanced Packaging Engine) is the infrastructure enabling the
grab() calls in Groovy, a set of classes leveraging Ivy to allow for a repository driven module system for Groovy. This allows a developer to write a script with an essentially arbitrary library requirement, and ship just the script. Grape will, at runtime, download as needed and link the named libraries and all dependencies forming a transitive closure when the script is run from existing repositories such as Ibiblio, Codehaus, and java.net.
This will likely make Groovy 1.7 rather than 1.6. The principal gating issue is Ivy. Ivy is in Beta1, and already for Beta2 there are breaking API changes. We need to wait for Ivy to at least start it's RC cycle before it is brought into the trunk.
- There must be a means to cause all calls to the Grape system to become no-ops and rely strictly on the JVM classpath.
- Grape should support bringing in packages from Maven 2 repositories.
- There should be some notion of 'endorsed modules' that are shortcutted in for easier use. For example: Scriptom, GroovyWS, SwingXBuilder. These can be hosted as regular Maven2 POMS or some other repository mechanism can be used.
- There should be command line tools similar to RubyGems, to add, remove, enumerate, and update versions of Grapes stored in the local cache.
- The implementation should not prevent movement into a container style module system such as integrating OSGi or Java 7 Super Packages. (this requirement should not be construed as an endorsement of either)
Code Level Support
Typically a call to grab will occur early in the script or in class initialization. This is to insure that the libraries are made available to the ClassLoader before the groovy code relies on the code. A couple of typical calls may appear as follows:
grab(Object self, String module)and
grab(Object self, HashMap attrs)will be added to the DGM so that references to the backing Grape classes will not be needed. These will be proxies to the main Grape class calls.
- Multiple calls to grab in the same context with the same parameters should be idempotent. However, if the same code is called with a different ClassLoader context then resolution may be re-run.
grabwill be disableable on a JVM level via a static field [TBD] whose initial value can be set by a system property [TBD]. Note that that property will only be queried the first time that the Grape settings class is resolved, so while it is settable at the command line level it may be re-set by code executing before the first call to grab.
grabrequires that a RootClassLoader or GroovyClassLoader be specified or be in the ClassLoader chain of the calling class. By default failure to have such a ClassLoader available will result in module resolution and an exception being thrown. A flag passed into the
grabcall can prevent the exception from being thrown. Preference for the ClassLoaders is
- The ClassLoader passed in via the
classLoader:argument and it's parent classloaders.
- The ClassLoader of the object passed in as the
referenceObject:argument, and it's parent classloaders.
- The ContextClassLoader of the Current Thread and its parent classloaders.
- The ClassLoader passed in via the
- [note, more elaboration needs to be done to describe how to insure the groovy class can use grab]
grab(String)is a shortcut for endorsed groovy modules and will be equivilant to
grab(group:'groovy.endorsed', module:<the module>, version:<the version of groovy being run>)
group:- <String> - Which module group the module comes from. Translates directly to a Maven groupId. Any group matching
/groovy(|\..|x|x\..)/is reserved and may have special meaning to the groovy endorsed modules.
module:- <String> - The name of the module to load. Translated directly to a Maven artifactId.
version:- <String> and possibly <Range> - The version of the module to use. Either a literal version ('1.1-RC3') or an Ivy Range ('2.2.1,' meaning 2.2.1 or any grater version). Grape may support simple ranges ('2.2.1'..'*') but supporting open ended ranges creates implementation level problems ('2.2.1'..<'3.0.0' meaning any version greater than 2.2.1 but no 3.x version).
classLoader:- <GroovyClassLaoder> or <RootClassLoader> - The ClassLoader to add resolved Jars to
referenceObject:- <Object> - The closest parent ClassLoader for the object's class will betreated as though it were passed in as
force:- <boolean>, default false - Whether to ignore cached versions of the module file or not.
transitive:- <boolean>, default true - Whether to resolve other dependencies this module has or not.
changing:- <boolean>, default false - Whether the artifact can change without it's version designation changing.
fail:- <boolean>, default true - If ClassLoader resolution or repository querying fails, should we throw an exception (true) or fail silently.
There are synonyms for some other above parameters. Submitting both is a runtime exception.
File Level View
The downloaded modules will be stored according to Ivy's standard mechanism with a cache root of
Command Line Tools
This installs/removes/updates the specified groovy module or maven artifact. If a version is specified for maven artifacts that specific version will be installed/removed/updated. If it isn't the latest stable version will be installed/upgraded or all versions will be removed.
Lists locally installed modules (with their full maven name in the case of groovy modules) and versions.
The motivation for introducing Grape into groovy is to resolve the library and module proliferation problem we are encountering. As a general purpose language Grape is suitable for a lot of wildly variable tasks. Providing groovy ways to do those things can crate 'bloat' because a large number of classes that are
Use of Maven Repositories
Maven is big, there are tons of Java libraries that are already deployed in a well-known infrastructure. Because almost all of these are straight Java they are all usable in Groovy out of the box.
Use of Ivy
- Ivy is licensed under the ASL2, which is the same license as Groovy
- Ivy is focused strictly on Repository Management. Maven has a strong Repository Management portion, but also has other aspects not germane to the needs of the Grape system, namely build management and project management. If the goal is to provide a means to drop unneeded code we shouldn't bring in unneeded code.
- Ivy provides for an extensible repository resolution system. If we decide to roll our own Groovy Repository we have the infrastructure to do it, we can also support other non-maven repository systems if needed.
GroovyStarter does do some existing library management, namely loading every singe jar in ~/.groovy/lib into the RootLoader. With Grape installed such behavior can continue, and is at worst duplicate effort and is fully backward compatibile. In the 2.0 timeframe we may want to look into deprecating or removing the auto-include of the ~/groovy/lib directory.
We may want to increase the kind of repositories that Grape can handle from simple Ivy and Maven repositories to other areas such as OSGi Repository Bundles and JNLP (WebStart) files and possibly to whatever mechanism the Consumer JRE (Java 6 Update N) uses to resolve it's classes.