Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

mvn versions:display-dependency-updates

The output is useful, but you still need to interpret it. In this case, there is a beta library that is suggested. Not.

INFO] ------------------------------------------------------------------------
[INFO] Building igs 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- versions-maven-plugin:2.1:display-dependency-updates (default-cli) @ igs ---
[INFO] The following dependencies in Dependency Management have newer versions:
[INFO]   commons-collections:commons-collections ............ 3.2.1 -> 20040616
[INFO]   org.hibernate:hibernate-validator ......... 5.0.1.Final -> 5.1.0.Beta1
[INFO]
[INFO]

In this case, a library with a version number that doesn’t follow the normal version patters is mistakenly noted as a newer version.

[INFO] ------------------------------------------------------------------------
[INFO] Building assets 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- versions-maven-plugin:2.1:display-dependency-updates (default-cli) @ assets ---
[INFO] The following dependencies in Dependency Management have newer versions:
[INFO]   commons-collections:commons-collections ............ 3.2.1 -> 20040616
[INFO]   org.hibernate:hibernate-validator ......... 5.0.1.Final -> 5.1.0.Beta1
[INFO]
[INFO]

February 7th, 2014

Posted In: Maven

Tags: , , , ,

Leave a Comment

The servlet 3.0 spec defines a way to share webapp JSP resources via a dependent jar (See Servlet 3.0 spec, section 10.5)

If you have a Maven dependency that is a jar, you can package resources and have them available to webapps that use them as a dependency.

To share, /css/test.css, you need to place it in:
/mavenModule/src/main/resources/META-INF/resources/css/test.css

Any webapp that depends on that jar can access /css/test.css as if it was in the root of it’s own webapp.

<link rel="stylesheet" type="text/css" href="<c:url value="/css/test.css" />">

Caveat, IntelliJ does not resolve /css/test.css as being within the current webapp. There was a ticket that was filed in 2011, but it doesn’t appear that it will ever be fixed.

Note, that if you are trying to use the included file as a tag file, it will need to have /WEB-INF/tags at the front of the included path.

January 24th, 2014

Posted In: IntelliJ, Maven, Servlet Spec

Leave a Comment

We had an existing Springframework web application that needed to handle images being stored in AmazonWS. Here are the changes taht I needed to make to add the new functionality.

  1. Add the AmazonWS Maven dependency
            <dependency>
                <groupId>com.amazonaws</groupId>
                <artifactId>aws-java-sdk</artifactId>
                <version>1.3.30</version>
            </dependency>
    
  2. Create the files that contain the AmazonWS credentials. Ours are stored in a webdav repository and we have different credentials per environment. To differentiate the files, I used the naming convention of amazon-.properties. The contents of the files were:
    # Fill in your AWS Access Key ID and Secret Access Key
    # http://aws.amazon.com/security-credentials
    accessKey=<nunya bidness>
    secretKey=<also nunya bidness>
    
  3. I created a Spring java configuration class.. Since our files are stored on a webdav and there is a webdav for each environment, I need to jump through some hoops in order to get the properties file.
    package com.appriss.jxp.amazon;
    
    import com.amazonaws.auth.PropertiesCredentials;
    import com.amazonaws.services.s3.AmazonS3Client;
    import com.appriss.justicexchange.commons.http.HttpUtils;
    import com.appriss.justicexchange.commons.utility.Environment;
    import com.appriss.justicexchange.commons.utility.Utility;
    import org.apache.commons.io.IOUtils;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.io.IOException;
    
    /**
     * Spring java configuration class for AmazonWS.
     * @author nshelton
     */
    @Configuration
    public class AmazonConfiguration {
    
        /**
         * Creates an Amazon S3 Client.
         * @return AmazonS3Client
         */
        @Bean
        public AmazonS3Client amazonS3Client() throws IOException {
            PropertiesCredentials propertiesCredentials = new PropertiesCredentials(
                IOUtils.toInputStream(
                    HttpUtils.getResponse(
                        Utility.getWebdavServer() + "/product/jxportal/config/amazon-" + Environment.getValue() + ".properties")));
            return new AmazonS3Client(propertiesCredentials);
        }
    }
    
  4. The Junit test class for this is very simple. Did it create a spring bean of the desired type.
    package com.appriss.jxp.amazon;
    
    import com.amazonaws.services.s3.AmazonS3Client;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.TestExecutionListeners;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
    
    import static org.junit.Assert.*;
    
    /**
     * Tests the Amazon configuration class.
     * @author nshelton
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
    @ContextConfiguration
    public class TestAmazonConfiguration {
    
        @Autowired
        private AmazonS3Client amazonS3Client;
    
        @Test
        public void testAmazonS3Client() {
            assertNotNull(amazonS3Client);
        }
    }
    
  5. We are going to use AmazonWS to create temporary URLs that will expire after a set amount of time. The timeout value is stored in another file on the webdav and is fronted by a PropertiesDao class that caches the value for a set amount of time so it will not bombard the webdav with too many requests, yet allows it to be changed at runtime. I extracted this logic into a method in a utility class.
    package com.appriss.jxp.amazon;
    
    import com.amazonaws.HttpMethod;
    import com.amazonaws.services.s3.AmazonS3Client;
    import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
    import com.appriss.jxp.properties.PropertiesDao;
    import org.joda.time.MutableDateTime;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    
    /**
     * Amazon utility class.
     * @author nshelton
     */
    @Component
    public class AmazonUtility {
    
        @Autowired
        private PropertiesDao propertiesDao;
    
        @Autowired
        private AmazonS3Client amazonS3Client;
    
        /**
         * Gets an AmazonWS url for the given resource.
         * @param bucket the value of the AmazonWS bucket
         * @param siteId the siteId of this request
         * @param s3FileName the name of the S3 resource to generate an expiring URL for
         * @return the expiring AmazonWS URL for the requested resource
         * @throws IOException
         */
        public String getUrl(String bucket, String siteId, String s3FileName) throws IOException {
            GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucket + siteId,
                                                                                                      s3FileName,
                                                                                                      HttpMethod.GET);
            MutableDateTime mutableDateTime = new MutableDateTime();
            mutableDateTime.add(Long.parseLong(propertiesDao.getProperty("amazonws.timeout")));
            generatePresignedUrlRequest.setExpiration(mutableDateTime.toDate());
    
            return amazonS3Client.generatePresignedUrl(generatePresignedUrlRequest).toString();
        }
    }
    
  6. Just to make things fun, where I need to use this is legacy code and doesn’t know anything about Springframework. The desired logic is for it to use the AmazonWS S3 to create URLs if the image has been stored there and IF that URL resolution has been turned on. It had been requested to make it possible for the use of AmazonWS to be turned off if the service isn’t responsive enough.
        public String getFormattedSigImageURL() {
            String formattedSigImageURL = null;
            // if I have the information needed to construct an AmazonWS URL
            if (StringUtils.isNotBlank(s3SignatureBucket) &amp;&amp; StringUtils.isNotBlank(s3ImageName)) {
                PropertiesDao propertiesDao = CommonTools.getBean(PropertiesDao.class);
                try {
                    // if the AmazonWS service is turned on
                    if ("true".equals(propertiesDao.getProperty("amazonws.enabled"))) {
                        AmazonUtility amazonUtility = CommonTools.getBean(AmazonUtility.class);
                        formattedSigImageURL = amazonUtility.getUrl(s3SignatureBucket, pharmacySiteId, s3ImageName);
                    }
                } catch (IOException ignore) {}
            }
    
            // not found, try another way
            if (StringUtils.isBlank(formattedSigImageURL)) {
                try {
                    formattedSigImageURL = CommonTools.getImageURL(sigImageURL);
                } catch (NamingException ignore) {
                    formattedSigImageURL = sigImageURL;
                }
            }
    
            return formattedSigImageURL;
        }
    

February 15th, 2013

Posted In: Java, JUnit, Maven, Spring

Leave a Comment

Updated on 2013/08/22

I added the maven-source-plugin and the maven-javadoc-plugin to my Maven projects. Great idea, but building the source and javadoc jar every time was increasing my build times. The solution is to specify a phase, then it will only run when the specified goal is ran in that phase instead of any phase that has that goal.

            <plugin>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.2.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.9.1</version>
                <executions>
                    <execution>
                        <id>attach-javadocs</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

February 8th, 2013

Posted In: Maven

One Comment

I had to update an Ant script that used Maven for artifact resolution. It had been working because the Maven settings.xml file for the build agent had been modified. When the agents were updated, the customizations were lost. To fix this, I updated the Ant script by letting it know where the repository was. I added the repository definition to the top of the script.

<artifact:remoteRepository id="remote.repository" url="http://artifactory.appriss.com/artifactory/repo/"/>

Then I added the following to each block.

<remoteRepository refid="remote.repository"/>

January 31st, 2013

Posted In: Ant, Maven

Leave a Comment

I never really understood the use of the bundleFileName in the maven-ear-plugin. Who looks inside the .ear anyway. Well, there is a reason it is there.

I had to set the finalName property in the build section of several Maven modules across several projects. I learned the hard way that Maven modules do not talk to each other. The maven-ear-plugin assumes that the name of the artifacts is the default name. If you use finalName to change the name of the artifact, it is not aware. It configures your ear, but the file that it points to for the ejb or war module will not be there. Doh!

Example of finalName usage in an ejb module:

    <build>
        <finalName>isgwebsupport</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <ejbVersion>3.0</ejbVersion>
                    <generateClient>true</generateClient>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

Example of finalName usage in a war module:

    <build>
        <finalName>isgwebsupport</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <!--
                        Needed for skinny war
                        http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html
                    -->
                    <packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

So, if you set the finalName of an ejb module or a web module, you must also set the bundleFileName in the ear module.

NOTE: You must specify the file extension when you use bundleFileName.

Example of the usage of bundleFileName in an ear module:

    <build>
        <finalName>isgwebsupport</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <version>5</version>
                    <description>ISGWebSupport</description>
                    <displayName>ISGWebSupport</displayName>
                    <defaultLibBundleDir>/lib</defaultLibBundleDir>
                    <skinnyWars>true</skinnyWars>
                    <modules>
                         <webModule>
							<groupId>${project.groupId}</groupId>
                            <artifactId>websupport-war</artifactId>
                            <contextRoot>/giswebsupport</contextRoot>
							<bundleFileName>isgwebsupport.war</bundleFileName>
                        </webModule>
                        <ejbModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>websupport-ejb</artifactId>
                            <bundleFileName>isgwebsupport.jar</bundleFileName>
                        </ejbModule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>

Lesson learned.

January 18th, 2013

Posted In: Maven

Tags: , , , , , , , , , ,

6 Comments

You would think that this would be terribly easy, but it isn’t. It took several attempts before I figured out what they wanted. Too bad their contextual help doesn’t give you the details.

Select the “Deploy” tab from the top, then select the “Artifacts Bundle” tab from the left. Choose the file you want, then hit deploy.

The tricky part is that they expect very specific things from the file. In my case, I was trying to import the artifact corresponding to

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>1.6.11</version>
</dependency>

What they don’t tell you is that the name of the file will be part of the groupId. So I ended up with an archive named org.zip. The contents of the archive were:
/aspectj
     /aspectjtools
          /1.6.11
               aspectjtools-1.6.11.jar
               aspectjtools-1.6.11.jar.sha1
               aspectjtools-1.6.11.pom
               aspectjtools-1.6.11.pom.sha1

In hindsight, I might have been able to name the archive org.aspectj.aspectjtools, then inside I could have multiple version directories, each containing their respective artifacts.

January 17th, 2013

Posted In: Maven

Tags: , , , ,

Leave a Comment

Maven EJB MODULES

EJB modules are just like normal, but they also have an manifest section:

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <ejbVersion>3.0</ejbVersion>
                    <generateClient>true</generateClient>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • manifest – this section is responsible for generating the manifest file and adding the classpath entries

MAVEN WEB MODULES

Do everything like you normally would, except you will need a build section like the following:

    <build>
        <plugins>
            <plugin>
                <!--
                    Needed for skinny war
                    http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html
                -->
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • packagingExcludes – tells the plugin to exclude the jar files from the lib directory
  • manifest – this section is responsible for generating the manifest file and adding the classpath entries

MAVEN EAR MODULE

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.appriss.justicexchange.licensemgr</groupId>
        <artifactId>licensemgr-parent</artifactId>
        <version>3.0-SNAPSHOT</version>
    </parent>

    <artifactId>licensemgr-ear</artifactId>
    <packaging>ear</packaging>

    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>licensemgr-ejb</artifactId>
            <version>${project.version}</version>
            <type>ejb</type>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>licensemgr-war</artifactId>
            <version>${project.version}</version>
            <type>war</type>
        </dependency>
        <!--
            Also include the war as a type=pom so that it pulls in the dependencies for inclusion in the ear /lib.
        -->
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>licensemgr-war</artifactId>
            <version>${project.version}</version>
            <type>pom</type>
        </dependency>
    </dependencies>

    <build>
        <finalName>licensemgr-${project.version}</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.7</version>
                <configuration>
                    <version>5</version>
                    <displayName>ISG License Manager Application</displayName>
                    <description>LicenseManager</description>
                    <defaultLibBundleDir>/lib</defaultLibBundleDir>
                    <skinnyWars>true</skinnyWars>
                    <modules>
                        <ejbModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>licensemgr-ejb</artifactId>
                        </ejbModule>
                        <webModule>
                            <groupId>${project.groupId}</groupId>
                            <artifactId>licensemgr-war</artifactId>
                            <contextRoot>licensemgr</contextRoot>
                            <bundleFileName>licensemgr-${project.version}.war</bundleFileName>
                        </webModule>
                    </modules>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

There should normally be a dependency entry for each module that will be packaged into the war. The EJB modules will be included with a of ejb and the WAR modules will be included with a of war. You ALSO need to add an extra dependency for each WAR module with a of pom. This will cause all of the dependencies to be pulled into the ear module and placed in the library bundle directory (/lib). If you don’t do this, you will need to duplicate each dependency of each war module as a dependency of the ear module.

The build section has 2 entries related to skinny wars:

  • defaultLibBundleDir – tells Maven where to bundle the jars
  • skinnyWars – tells Maven that you intend to make skinny wars

January 4th, 2013

Posted In: Java, Maven

Tags: , , , , , ,

2 Comments

Even if you upload a settings.xml into the Maven configuration of TeamCity, it still defaults to use the “default” settings.xml that it came with. It is a plain settings.xml that is basically useless. You have to select the Maven settings file from the drop-down on the Maven settings page for each and every project. So much for convention over configuration.

December 4th, 2012

Posted In: Maven, TeamCity

Leave a Comment

The project finally got so large that the JUnit tests would run out of heap space during the tests. I added space to the IDEA maven runner, but that didn’t work. You have to add it to the maven-surefire plugin.

<plugin>                                            
    <groupId>org.apache.maven.plugins</groupId>     
    <artifactId>maven-surefire-plugin</artifactId>  
    <version>2.12.3</version>                       
    <configuration>                                 
        <argLine>-Xms512m -Xmx512m</argLine>        
    </configuration>                                
</plugin>                                           

September 11th, 2012

Posted In: Java, JUnit, Maven

Leave a Comment

« Previous PageNext Page »
LinkedIn Auto Publish Powered By : XYZScripts.com