Artifact Size. A story of size enforcement.

So it looks like I’ve not been posting here for quite some time. Last post was in 2017…

The maven enforcer on the binary size can be a very useful tool as well as disruptive and close to useless. I think, in this world of cloud deployment and containers it’s getting again useful as you want a microservice to be as little as possible and be aware if it breaks a certain limit.

I said it: a microservice. What if you are working on a HUGE monolith comprised by 185 different OSGi bundles and God only knows how many other form of binary content are distributed in there?

In this last case, you may have a limit, with some margin and then the size is creeping closer and closer to the limit. Then you send your PR, which increase the size by just 2KB and BANG! Fails the check. WTF! You sure think… not my fault. Why on earth… regardless.

The point now is to find if there has been any commit which pushed the size considerably in the “recent past”. A task that done by hand can be tedious and error prone. So here’s another script. With a very imaginative name: artifact-size.sh.

What it does is fairly simple. it takes 3 mandatory parameters: repo, name and numer of commits. Repo is the path to a local git clone of the project, name is the relative path to the generated artifact (the jar) and number of commits is, well…, the number of commits you want to go back in time.

Don’t worry, if just invoke it without any parameter it will give you a help.

It will then take that number of commits, go back in time and start working forwards one commit a time packaging your project and collecting in target/ a CSV with the meaningful info like: commit hash, size and something more. You can then open this CSV file in open office (for example) and start playing with filters, putting it through a complex pipe of bash command or, why not, read it as it is.

If you’re lucky like me, you can find a single commit pushing considerably the size (20MB+) and therefore can work with the developer on what can be done (reverting?).

Potential future improvements? Here are some ideas and PR are always welcome

  • get a % of increase as argument and flag already any commit that goes beyond such threshold.
  • take the above % and work with bisect pinning down the first commit that bumped the size beyond such threshold.

https://github.com/davidegiannella/misc/blob/master/artifact-size.sh

Maven release plugin and local changes

It may happen that you’re trying to fix some issues that affects the release of a maven project and therefore you apply some changes locally and then run

mvn release:prepare -DdryRun=true -Darguments=-DskipTests

Then you get an error message like

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.5.3:prepare (default-cli) on project jackrabbit-oak: Cannot prepare the release because you have local modifications :
[ERROR] [oak-api/src/main/java/org/apache/jackrabbit/oak/api/PropertyState.java:modified]
[ERROR] [oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/CacheStatsMBean.java:modified]
[ERROR] [oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/CheckpointMBean.java:modified]
[ERROR] [oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/IndexStatsMBean.java:modified]
[ERROR] [oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/RepositoryStatsMBean.java:modified]

Sure. release-plugin is giving you an extra check about any local changes that may not end in the release. However you don’t want to commit those changes to the SCM just yet; you want first to see if they works.

A “quick” workaround is on the command line in the (verbose) form of

mvn release:prepare -DdryRun=true -Darguments=-DskipTests -DcheckModificationExcludeList=oak-api/src/main/java/org/apache/jackrabbit/oak/api/*,oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/*

You can as well specify something in the poms directly however I never had the need.

References:

 

CQ5 Maven Archetype

Add the Adobe profile in your ~/.m2/settings.xml

    <profile>
      <id>adobe-public</id>
      <activation>
        <activeByDefault>false</activeByDefault>
      </activation>
      <properties>
        <releaseRepository-Id>adobe-public-releases</releaseRepository-Id>
        <releaseRepository-Name>Adobe Public Releases</releaseRepository-Name>
        <releaseRepository-URL>http://repo.adobe.com/nexus/content/groups/public</releaseRepository-URL>
      </properties>
      <repositories>
        <repository>
          <id>adobe-public-releases</id>
          <name>Adobe Basel Public Repository</name>
          <url>http://repo.adobe.com/nexus/content/groups/public</url>
          <releases>
            <enabled>true</enabled>
            <updatePolicy>never</updatePolicy>
          </releases>
          <snapshots>
            <enabled>false</enabled>
          </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>adobe-public-releases</id>
          <name>Adobe Basel Public Repository</name>
          <url>http://repo.adobe.com/nexus/content/groups/public</url>
          <releases>
            <enabled>true</enabled>
            <updatePolicy>never</updatePolicy>
          </releases>
          <snapshots>
            <enabled>false</enabled>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>

Creating a multi-module project:

mvn archetype:generate -DarchetypeGroupId=com.day.jcr.vault \
 -DarchetypeArtifactId=multimodule-content-package-archetype \
 -DarchetypeVersion=1.0.0 \
 -DarchetypeRepository=adobe-public-releases \
 -P adobe-public

Check about any update to the archetypeVersion.

For not specifying the profile at every mvn command add to the ${project}/pom.xml (the parent one). This is no longer needed with archetype 1.0.2+

   <repositories>
     <repository>
         <id>adobe-ext.hoc</id>
         <name>Adobe External Central Repository</name>
         <url>http://repo.adobe.com/nexus/content/groups/public</url>
     </repository>
   </repositories>
   <pluginRepositories>
      <pluginRepository>
          <id>adobe-public-releases</id>
          <name>Adobe Basel Public Repository</name>
          <url>http://repo.adobe.com/nexus/content/groups/public</url>
          <releases>
              <enabled>true</enabled>
              <updatePolicy>never</updatePolicy>
          </releases>
          <snapshots>
              <enabled>false</enabled>
          </snapshots>
      </pluginRepository>
   </pluginRepositories>

In ${project}/pom.xml check the content-package-maven-plugin pluging version. For example the content-package plugin in the archetype is 0.0.13 but as at 10th September 2012 the latest one is 0.0.19

To install everything execute from the root project

sampleapp$ mvn install -P autoInstallPackage

To install only the bundle

sampleapp/bundle$ mvn sling:install

To install only the content package

sampleapp/content$ mvn install -P autoInstallPackage

Adding some exclude filtering to the contet package to avoid any spurius includes.

In sampleapp/content/pom.xml replace the exclude section with the
following

<excludes>
    <exclude>**/.vlt</exclude>
    <exclude>**/.vltignore</exclude>
    <exclude>**/*.iml</exclude>
    <exclude>**/.classpath</exclude>
    <exclude>**/.project</exclude>
    <exclude>**/.DS_Store</exclude>
    <exclude>**/target/**</exclude>
    <exclude>libs/**</exclude>
</excludes>

Optional step

Personally I don’t like a package name like “sampleapp-content-x.y.z”
as I’m actually deploying a codebase and not content. So I find it a
bit misleading. In order to have the package named as
“sampleapp-codebase-x.y.z” in the sampleapp/content/pom.xml in the
build->plugin->configuration for the content-package-maven-pluing add
the name and finalName definition as following

<plugin>
  <groupId>com.day.jcr.vault</groupId>
  <artifactId>content-package-maven-plugin</artifactId>
  <extensions>true</extensions>
  <configuration>
    <name>sampleapp-codebase</name>
    <finalName>sampleapp-codebase</finalName>
    <failOnError>true</failOnError>
...

Maven import

if you’re using CQ 5.5+ you can avoid checking and importing each dependency version by using the com.day.cq:cq-quickstart-product-dependencies dependency in parent pom.

JSP Support in Eclipse

Don’t forget to add the JSP support for eclipse by following: How to work with JSP.

In eclipse then by converting the project to a faceted, dynamic web project and with the proper context root path you’ll have the proper JSP support. Don’t forget to delete the rubbish that eclipse puts in when converting to a dynamic web project.

Screen Shot 2013-10-16 at 12.35.55

Screen Shot 2013-10-16 at 12.36.14

References

http://dev.day.com/docs/en/cq/current/core/how_to/how_to_use_the_vlttool/vlt-mavenplugin.html

Weekly Links 2010-41

Ok this week I didn’t have much time for reading the net, however here are some interesting links

5 things you didn’t know about … Apache Maven

La libertà non ha prezzo: come liberarsi di GMail (Italian)

Announcing Amino, a new UI toolkit for Desktop Java

Oracle and IBM Collaborate to Accelerate Java Innovation Through OpenJDK

Oracle’s strategy is now clear

IBM and Oracle to Collaborate on OpenJDK

Peace breaks out?!?

Maven Dependecy JAR Configuration

Use JavaFX to quickly create applications

How free is the OpenJDK?

Mockito – Pros, Cons, and Best Practices

Weekly links 2010-32

During these weeks I was too busy for contributing the weekly link. Here it is one for this week 🙂

Maven is good, but needs some love

…But Maven needs a proper and clean environment…

Functional Programming Concepts in JDK 7 | Javalobby

Kent Beck’s Test Driven Development Screencasts

Following the recommendations of Corey Haines, Michael Guterl, James Martin and Michael Hunger I decided to get Kent Beck’s screencasts on Test Driven Development which have been published by the Pragmatic Programmers.

Testing REST Web Services With JPA and Spring

REST Web Services can be particularly difficult to test, with the need for networking, a web container, multiple threads and transaction management creating extra complexity beyond your standard unit test. In this article I demonstrate patterns designed to address this complexity while enabling complete testing of your REST web service stack.

Oracle shuts down open source test servers

No One Nos: Learning to Say No to Bad Ideas

No. One word, a complete sentence. We all learned to say it around our first birthday, so why do we have such a hard time saying it now when it comes to our work?

Kick Ass Kickoff Meetings

Every meeting is an opportunity. Why waste your first one?

5 things you didn’t know about … Java Database Connectivity

JDBC is more than a background player in database connectivity. The more you know about it, the more efficient your RDBMS interactions will be.

Have you upgraded your Java 1.6_21 to Java 1.6_21?

Selenium 2/Web Driver – the land where Page Objects are king!

12 Things A Programmer Really Needs To Know

URL-based Locale

Spring Reading – Getting Started with Spring Framework

Specify proxy in Maven

I’ve just started using Maven, and I suddenly stub into a problem where maybe everybody in big corporate have stubbed: connecting through a proxy.

Maven can connect to internet through an HTTP proxy that support basic authentication. In order to specify it, just create (or modify if exist) the file ~/.m2/settings.xml in the following way:

<settings>
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>put.here.the.proxy.address</host>
<port>3128</port>
<username>yourUserName</username>
<password>yourPassword</password>
<nonProxyHosts /> <!– useful for location to make bypassed by proxy –>
</proxy>
</proxies>
</settings>

That’s it! 🙂