Showing posts with label Maven. Show all posts
Showing posts with label Maven. Show all posts

Thursday, 3 November 2022

Maven: Where did it come from?

Just a small note.

So, I started using StringUtils in my code. It's from the apache.commons.lang3 package.

Then I noticed that I am not actually using this dependency in my pom.

So I'm using a transitive dependency, which is basically a bad habit, as this transitive dependency can suddenly change.

So I need to find which transitive dependency it is, and add it to my local pom, just to be sure.

The Maven dependency in question is:

org.apache.commons:commons-lang3:3.4

A little research and it turns out mvn dependency:tree is very nice.

You get something like:

So, as it turns out commons-lang3 is a transitive dependency of info.blii.wiki:bliki-core:jar:3.1.0

Well, that's a relief, that is.

References

StackOverflow - In Maven 2, how do I know from which dependency comes a transitive dependency?
https://stackoverflow.com/questions/34144/in-maven-2-how-do-i-know-from-which-dependency-comes-a-transitive-dependency

Thursday, 24 May 2018

Hello World with Maven

Getting started with Maven is slightly complicated, so I thought I'd write down some links1 2 on how to get up and running quickly with a simple HelloWorld Java application with Maven archetypes.

That and I wanted to tell how to upgrade the Java version used for the Maven project. There seem to be different ways to do it. Some easy, some hard.

Groupidorg.apache.maven
Artifactidthe name of the jar without version, for example maven, commons-math
Version2.0
mvn archetype:generate -DgroupId=com.mrbear -DartifactId=mrbear -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

Verify that this is the latest archetype version4.

Upgrading to Java 8

One way is to add the versions to the properties in the pom.xml, which is easiest.

<properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
</properties>

Another way is to change the maven compiler plugin to use the new version, which is harder.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

References

[1] Apache Maven Project - Creating a simple java application
https://maven.apache.org/plugins-archives/maven-archetype-plugin-1.0-alpha-7/examples/simple.html
[2] Apache Maven Project - Maven in 5 Minutes
https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html
[3] Apache Maven Project - Setting the -source and -target of the Java Compiler
https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html
[4] Apache - Maven Archetype Quickstart Summary
http://maven.apache.org/archetypes/maven-archetype-quickstart/summary.html

Thursday, 18 January 2018

An error has occurred in JavaDocs report generation

Well, it turns out that this blog1 is an almost word-for-word mirror of an article2 about using Maven and Java 8 to generate the JavaDocs.

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12.431 s
[INFO] Finished at: 2017-05-17T21:13:32+02:00
[INFO] Final Memory: 21M/157M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:2.9.1:javadoc (default-cli) on project mrbear: An error has occurred in JavaDocs report generation:
[ERROR] Exit code: 1 - /home/mrbear/beargame/src/main/java/awesomeness/vaadin/editor/Buttons.java:56: warning: no description for @return
[ERROR] * @return
[ERROR] ^

Turns out Malformed HTML is now a thing that bombs your javadoc generation. Add "-Xdoclint:none" somewhere to turn this off.

References

[1] Stephen Colebourne's blog - Turning off doclint in JDK 8 Javadoc
http://blog.joda.org/2014/02/turning-off-doclint-in-jdk-8-javadoc.html
[2] NLJUG Java Magazine
http://www.nljug.org/

Thursday, 23 March 2017

AssertJ vs. Hamcrest

I recently came across a piece of code that used a Stack1. The Stack seems to inherit from Vector. The JavaDoc indicated (and so did my IDE, I think) that I should be using the Deque2 interface instead. To be precise:
“A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class.”
Dequeue basically seems to be a specialized Queue3, that supports element insertion and removal at both ends4.

In order to get to grips with Deque, I decided to write some simple tests. These are JUnit Tests (version 4.12) and in one I used Hamcrest5 and in the other I went for AssertJ6.

Let's see what happens.

A simple compare

Hamcrest:
assertThat(actual, equalTo(testdata2));
AssertJ:
assertThat(actual).isEqualTo(testdata2);

Collections

Hamcrest:
assertThat(transmittedTestdata, hasSize(2));
AssertJ:
assertThat(transmittedTestdata).size().isEqualTo(2);

Null Values

Hamcrest:
assertThat(actual, not(nullValue()));
AssertJ:
assertThat(actual).isNotNull();

Exceptions

Hamcrest:
@Test(expected = NoSuchElementException.class)
public void testEmptyDequeueException()
{
  Deque<Testdata> transmittedTestdata = new ConcurrentLinkedDeque<>();
  Testdata pop = transmittedTestdata.pop();
}
AssertJ:
assertThatThrownBy(transmittedTestdata::pop).isInstanceOf(NoSuchElementException.class);

Imports

A comparison between the required imports of Hamcrest and Assertj is interesting:
Hamcrest:
import java.util.Deque;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedDeque;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
AssertJ:
import java.util.Deque;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedDeque;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

Notes

  • I really like the AssertJ fluent API. It feels more natural to me than the Hamcrest one.
  • It is way easier to find the appropriate matchers in AssertJ. I get the full benefit of my IDE code completion.
  • Adding the appropriate import is way easier. Using Hamcrest, I always get a choice of five different imports for the same matcher.
  • I need fewer imports anyways.
So far, I like AssertJ a lot.

I need to work with AssertJ a lot more, to see some of the interesting stuff.

References

[1] Java 7 JavaDoc - Stack
https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html
[2] Java 7 JavaDoc - Deque
https://docs.oracle.com/javase/7/docs/api/java/util/Deque.html
[3] Java 7 JavaDoc - Queue
https://docs.oracle.com/javase/7/docs/api/java/util/Queue.html
[4] Wikipedia - Double-ended queue
https://en.wikipedia.org/wiki/Double-ended_queue
[5] Hamcrest - Matchers that can be combined to create flexible expressions of intent
http://hamcrest.org/
[6] AssertJ - Quick start
http://joel-costigliola.github.io/assertj/assertj-core-quick-start.html

Thursday, 2 March 2017

Maven and the Dangers of Snapshots

Recently we've been causing problems in the regular builds of branches of our software.

Basically the problem is our own fault and is related to Maven Snapshots.

According to the guide1, a Snapshot is a library that is still under development, and may change rapidly as new versions of the Snapshot are pushed to the Nexus regularly.

If a dependency on a Snapshot is defined in your pom.xml, then Maven, as it should, always picks the latest Snapshot.

This is fine and dandy if you are currently developing your software, and you want the newest of the new of the libraries that your other software teams are developing.

The Problem

It means that once you create a stable release of your software (and the appropriate Git branch for it to live in as well, of course) it is important to replace the Snapshot in the pom.xml with the appropriate released version.

We neglected to do just that.

The Consequence

Our branch containing the release version of our software suddenly bombed with compile errors in the Deployment Pipeline.

This caused the maintenance people a headache, as the Git revision of the branch had not changed, between the previous build (which compiled just fine) and the new build (which bombed).

Despite the build being pulled from Git with the exact same revision, it was technically different from the previous build.

All because we kept developing the Snapshot and pushing it into the Nexus.

What we should have done

  • create a proper release of the library
  • change the pom.xml in the branch to refer to this release.
  • create a new snapshot of the library
  • use the new snapshot in the pom.xml of the master branch (which is used for development)
Now the build of both the branch as well as the master should compile again.

References

[1] Apache Maven - Getting Started
https://maven.apache.org/guides/getting-started/
Continuous Releasing of Maven Artifacts
https://dzone.com/articles/continuous-releasing-maven
Update: reference added.

Thursday, 28 January 2016

Liferay Themes

This is a followup of the blog entry about Liferay1 2 3.

As I wished to tailor the website layout of my Liferay instance, I started looking at themes. What I found was a bit of a surprise for me, as it seems themes for Liferay needs to be compiled/build using ant or maven.

There is a big body of documentation regarding the creation of Themes, but the procedure seems a bit brittle. It uses ant, needs to be able to reach the files of the classic theme, is dependent of the type of Application Server you are using, and a bit of other stuff.

Below are some of the error messages I got and had to solve before I got anything that worked.

Creating a Theme with Ant

  • Download the Plugins SDK that compiles new themes (and plugins) using Ant.
  • Create a properties file like build.<username>.properties
    [glassfish@localhost glassfish]$ cat liferay-plugins-sdk-6.2/build.glassfish.properties
    app.server.type=glassfish
    app.server.parent.dir=/home/glassfish
    app.server.glassfish.dir=${app.server.parent.dir}/glassfish4/glassfish
    javac.compiler=modern
  • In this directory, there should be a directory themes, where we can create our new theme6.
    [glassfish@localhost themes]$ ./create.sh mine "Mine"
    Parallel execution with configuration on demand is an incubating feature.
    :createTheme

    BUILD SUCCESSFUL

    Total time: 2.377 secs
  • Changed the build.xml in mine-theme, to use 'classic' as the parent theme.
    <property name="theme.parent" value="classic" />
    If you create your own theme with the Plugins SDK, place the icon in themes/Your_theme/docroot/_diffs/images/favicon.ico if you want to have your own favicon to bookmark.
  • Then "ant war"
  • Then "ant deploy" (or just copy the war into glassfish4/deploy)
The first problem I ran into was a problem with the xml file.
[2015-09-19T20:45:06.136+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506136] [levelValue: 800] [[
20:45:06,136 INFO  [AutoDeployer][HotDeployEvent:145] Plugin mine-theme requires marketplace-portlet]]

[2015-09-19T20:45:06.142+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506142] [levelValue: 800] [[
20:45:06,136 INFO  [AutoDeployer][HotDeployImpl:217] Deploying mine-theme from queue]]

[2015-09-19T20:45:06.149+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506149] [levelValue: 800] [[
20:45:06,142 INFO  [AutoDeployer][PluginPackageUtil:1016] Reading plugin package for mine-theme]]

[2015-09-19T20:45:06.193+0000] [glassfish 4.1] [INFO] [] [javax.enterprise.web] [tid: _ThreadID=140 _ThreadName=AutoDeployer] [timeMillis: 1442695506193] [levelValue: 800] [[
WebModule[null] ServletContext.log():Initializing Spring root WebApplicationContext]]

[2015-09-19T20:45:06.204+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506204] [levelValue: 800] [[
20:45:06,204 INFO  [AutoDeployer][ThemeHotDeployListener:98] Registering themes for mine-theme]]

[2015-09-19T20:45:06.236+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506236] [levelValue: 800] [[
20:45:06,228 ERROR [AutoDeployer][ThemeLocalServiceImpl:278] com.liferay.portal.kernel.xml.DocumentException: Error on line 8 of document  : Element type "theme" must be followed by either attribute specifications, ">" or "/>". Nested exception: Element type "theme" must be followed by either attribute specifications, ">" or "/>".
com.liferay.portal.kernel.xml.DocumentException: Error on line 8 of document  : Element type "theme" must be followed by either attribute specifications, ">" or "/>". Nested exception: Element type "theme" must be followed by either attribute specifications, ">" or "/>".
at com.liferay.portal.xml.SAXReaderImpl.read(SAXReaderImpl.java:429)
at com.liferay.portal.xml.SAXReaderImpl.read(SAXReaderImpl.java:447)
at com.liferay.portal.kernel.xml.SAXReaderUtil.read(SAXReaderUtil.java:187)
at com.liferay.portal.service.impl.ThemeLocalServiceImpl._readThemes(ThemeLocalServiceImpl.java:472)
at com.liferay.portal.service.impl.ThemeLocalServiceImpl.init(ThemeLocalServiceImpl.java:272)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:115)
at com.liferay.portal.spring.transaction.DefaultTransactionExecutor.execute(DefaultTransactionExecutor.java:62)
at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:51)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ServiceBeanAopProxy.invoke(ServiceBeanAopProxy.java:175)
at com.sun.proxy.$Proxy269.init(Unknown Source)
at com.liferay.portal.service.ThemeLocalServiceUtil.init(ThemeLocalServiceUtil.java:118)
at com.liferay.portal.deploy.hot.ThemeHotDeployListener.doInvokeDeploy(ThemeHotDeployListener.java:103)
at com.liferay.portal.deploy.hot.ThemeHotDeployListener.invokeDeploy(ThemeHotDeployListener.java:49)
at com.liferay.portal.deploy.hot.HotDeployImpl.doFireDeployEvent(HotDeployImpl.java:227)
at com.liferay.portal.deploy.hot.HotDeployImpl.fireDeployEvent(HotDeployImpl.java:96)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil.fireDeployEvent(HotDeployUtil.java:28)
at com.liferay.portal.kernel.servlet.PluginContextListener.fireDeployEvent(PluginContextListener.java:164)
at com.liferay.portal.kernel.servlet.PluginContextListener.doPortalInit(PluginContextListener.java:154)
at com.liferay.portal.kernel.util.BasePortalLifecycle.portalInit(BasePortalLifecycle.java:44)
at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:74)
at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:58)
at com.liferay.portal.kernel.util.BasePortalLifecycle.registerPortalLifecycle(BasePortalLifecycle.java:54)
at com.liferay.portal.kernel.servlet.PluginContextListener.contextInitialized(PluginContextListener.java:116)
at org.apache.catalina.core.StandardContext.contextListenerStart(StandardContext.java:5394)
at com.sun.enterprise.web.WebModule.contextListenerStart(WebModule.java:743)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:5932)
at com.sun.enterprise.web.WebModule.start(WebModule.java:691)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1041)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:1024)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:747)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:2286)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1932)
at com.sun.enterprise.web.WebApplication.start(WebApplication.java:139)
at org.glassfish.internal.data.EngineRef.start(EngineRef.java:122)
at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:291)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:352)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:500)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:539)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:360)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:360)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846)
at org.glassfish.deployment.autodeploy.AutoOperation.run(AutoOperation.java:164)
at org.glassfish.deployment.autodeploy.AutoDeployer.deploy(AutoDeployer.java:597)
at org.glassfish.deployment.autodeploy.AutoDeployer.deployAll(AutoDeployer.java:484)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:412)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:403)
at org.glassfish.deployment.autodeploy.AutoDeployService$1.run(AutoDeployService.java:233)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Caused by: org.dom4j.DocumentException: Error on line 8 of document  : Element type "theme" must be followed by either attribute specifications, ">" or "/>". Nested exception: Element type "theme" must be followed by either attribute specifications, ">" or "/>".
at org.dom4j.io.SAXReader.read(SAXReader.java:482)
a]]

[2015-09-19T20:45:06.236+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=140 _ThreadName=Thread-8] [timeMillis: 1442695506236] [levelValue: 800] [[
t org.dom4j.io.SAXReader.read(SAXReader.java:365)
at com.liferay.portal.xml.SAXReaderImpl.read(SAXReaderImpl.java:426)
... 82 more]]
Seems the problem was Quotes (") around the name of the theme "Mine" in the docroot/WEB-INF/liferay-plugin-package.properties file. Removed quotes, and things get picked up now.

Creating a Theme with Maven

mvn archetype:generate \
    -DarchetypeArtifactId=liferay-theme-archetype \
    -DarchetypeGroupId=com.liferay.maven.archetypes \
    -DarchetypeVersion=6.1.0 \
    -DartifactId=sample-theme \
    -DgroupId=com.liferay.sample \
    -Dversion=1.0-SNAPSHOT
I tried with Maven4 5 instead of Ant to develop a theme, but I couldn't rightly get it to work. Needs some time to work on it.

Uploading a theme

So there's a war file created containing the files. You can deploy the file into the application server.

There are several ways to do this. You can upload it to glassfish4/glassfish/domains/domain1/autodeploy.

But I find that in some cases the theme is not recorded by Liferay. Liferay listens to specific directories for new war files that are theme related. In my case the additional directory could well be glassfish4/deploy, because glassfish4 is the "home" of Liferay in my case.

You can verify if the theme was successfully picked up in your glassfish server log. You should see something lke:
[2016-01-11T14:38:26.668+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523106668] [levelValue: 800] [[
14:38:26,667 INFO  [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][AutoDeployDir:204] Processing mine-theme-6.2.0.1.war]]

[2016-01-11T14:38:26.673+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523106673] [levelValue: 800] [[
14:38:26,673 INFO  [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][ThemeAutoDeployListener:51] Copying themes for /home/glassfish/glassfish4/deploy/mine-theme-6.2.0.1.war]]

[2016-01-11T14:38:26.723+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523106723] [levelValue: 800] [[
14:38:26,722 INFO  [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][BaseDeployer:863] Deploying mine-theme-6.2.0.1.war]]

[2016-01-11T14:38:27.119+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107119] [levelValue: 800] [[
Expanding: /home/glassfish/glassfish4/deploy/mine-theme-6.2.0.1.war into /tmp/20160111143826861]]

[2016-01-11T14:38:27.563+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107563] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF]]

[2016-01-11T14:38:27.568+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107568] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF]]

[2016-01-11T14:38:27.581+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107581] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF/classes]]

[2016-01-11T14:38:27.589+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107589] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF/classes]]

[2016-01-11T14:38:27.606+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107606] [levelValue: 800] [[
Copying 1 file to /tmp/20160111143826861/WEB-INF]]

[2016-01-11T14:38:27.760+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107760] [levelValue: 800] [[
14:38:27,760 INFO  [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][BaseDeployer:2391] Modifying Servlet 2.4 /tmp/20160111143826861/WEB-INF/web.xml]]

[2016-01-11T14:38:27.860+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523107860] [levelValue: 800] [[
Building war: /tmp/20160111143827761]]

[2016-01-11T14:38:28.307+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523108307] [levelValue: 800] [[
Deleting directory /tmp/20160111143826861]]

[2016-01-11T14:38:28.331+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=112 _ThreadName=Thread-8] [timeMillis: 1452523108331] [levelValue: 800] [[
14:38:28,330 INFO  [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][ThemeAutoDeployListener:57] Themes for /home/glassfish/glassfish4/deploy/mine-theme-6.2.0.1.war copied successfully. Deployment will start in a few seconds

[2016-01-11T14:38:29.675+0000] [glassfish 4.1] [INFO] [NCLS-DEPLOYMENT-02027] [javax.enterprise.system.tools.deployment.autodeploy] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523109675] [levelValue: 800] [[
Selecting file /home/glassfish/glassfish4/glassfish/domains/domain1/autodeploy/mine-theme.war for autodeployment]]

[2016-01-11T14:38:30.239+0000] [glassfish 4.1] [INFO] [] [javax.enterprise.system.tools.deployment.common] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523110239] [levelValue: 800] [[
visiting unvisited references]]

[2016-01-11T14:38:31.349+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523111349] [levelValue: 800] [[
14:38:31,348 INFO  [AutoDeployer][HotDeployEvent:145] Plugin mine-theme requires marketplace-portlet]]

[2016-01-11T14:38:31.350+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523111350] [levelValue: 800] [[
14:38:31,349 INFO  [AutoDeployer][HotDeployImpl:217] Deploying mine-theme from queue]]

[2016-01-11T14:38:31.350+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523111350] [levelValue: 800] [[
14:38:31,350 INFO  [AutoDeployer][PluginPackageUtil:1016] Reading plugin package for mine-theme]]

[2016-01-11T14:38:31.404+0000] [glassfish 4.1] [INFO] [] [javax.enterprise.web] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523111404] [levelValue: 800] [[
WebModule[null] ServletContext.log():Initializing Spring root WebApplicationContext]]

[2016-01-11T14:38:31.414+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523111414] [levelValue: 800] [[
14:38:31,413 INFO  [AutoDeployer][ThemeHotDeployListener:98] Registering themes for mine-theme]]

[2016-01-11T14:38:33.507+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=221 _ThreadName=Thread-8] [timeMillis: 1452523113507] [levelValue: 800] [[
14:38:33,507 INFO  [AutoDeployer][ThemeHotDeployListener:113] 1 theme for mine-theme is available for use]]

[2016-01-11T14:38:33.736+0000] [glassfish 4.1] [INFO] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523113736] [levelValue: 800] [[
Loading application [mine-theme] at [/mine-theme]]]

[2016-01-11T14:38:33.992+0000] [glassfish 4.1] [INFO] [] [javax.enterprise.system.core] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523113992] [levelValue: 800] [[
mine-theme was successfully deployed in 4,148 milliseconds.]]

[2016-01-11T14:38:33.998+0000] [glassfish 4.1] [INFO] [NCLS-DEPLOYMENT-02035] [javax.enterprise.system.tools.deployment.autodeploy] [tid: _ThreadID=221 _ThreadName=AutoDeployer] [timeMillis: 1452523113998] [levelValue: 800] [[
[AutoDeploy] Successfully autodeployed : /home/glassfish/glassfish4/glassfish/domains/domain1/autodeploy/mine-theme.war.]]

Setting your theme

See Control Panel -> Configuration -> Portal settings -> Display Settings and below there's Look & Feel.

Also, there's this place: Control Panel -> Sites -> Your site -> Site Pages -> Look and Feel + Current Theme. You can select another theme from a list below in the same configuration page.

Your theme is actually a Plugin, and can be found among the Theme Plugins. Navigate to Control Panel -> Apps -> Plugins Configuration. Select the tab "Theme Plugins". Your theme should be visible in the list.

If not, you are likely to receive something like this in your logs7 8:
[2015-12-31T23:38:41.633+0000] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=29 _ThreadName=Thread-8] [timeMillis: 1451605121633] [levelValue: 800] [[
23:38:41,633 WARN [http-listener-1(4)][ThemeLocalServiceImpl:156] No theme found for specified theme id mine_WAR_minetheme. Returning the default theme.]]
I don't know why this happened in my case, but I found a reference in the Liferay database to the old mine-theme. Even though I thought I got rid of it permanently, but removing it from the autodeploy directory. If I remove it from the glassfish autodeploy directory, it is also removed from the Application Server. Liferay is listening to what happenes on the autodeploying front, detects the deletion, and starts cleaning up after itself as well.

Apparently, there still was an entry left hanging. I had to update the database manually to reset a database tablerow back to "classic".

Adapting your theme

It is possible to adapt your theme, by replacing images and css and html files judiciously.

The interesting bit of theming is that you specify the parent theme. So, you've got "styled" and "unstyled" and the default theme called "classic" to choose from. But it would also be easy to create for example a "Christmas" theme, that is derived from the theme that you normally use. So it's kind of an Inheritance structure, similar to Object Oriented Programming.

I also like the fact that in your new theme you specify the "changes" compared to the parent theme in the _diffs folder. This way, when a parent theme changes (upon a new release of Liferay Portal), you automatically get the new updates, and if you do not change these defaults in your theme, they are just build into the target war upon the next release.

If you wish to start making bigger changes, there is the possibility of using the Liferay Application Display Templates9 (ADT).

Liferay uses Apache Velocity10 as its templating engine.

Adding JQuery to the Liferay portal can be done as described at [11].

References

[1] Randomthoughts - Liferay
http://randomthoughtsonjavaprogramming.blogspot.nl/2015/12/liferay.html
[2] Liferay
http://www.liferay.com/
[3] Wikipedia - Liferay
https://en.wikipedia.org/wiki/Liferay
[4] Liferay Company Blogs - Creating Liferay Themes with Maven
https://www.liferay.com/web/mika.koivisto/blog/-/blogs/creating-liferay-themes-with-maven#_33_message_13069757
[5] Liferay Developer Network - Developing Liferay Theme Plugins with Maven
https://dev.liferay.com/develop/tutorials/-/knowledge_base/6-2/developing-liferay-theme-plugins-with-maven
[6] Liferay Developer Network - Creating a Theme Project in the Plugins SDK
https://dev.liferay.com/develop/tutorials/-/knowledge_base/6-2/creating-a-theme-project-in-the-plugins-sdk
[7] StackOverflow - Error occures when deploying theme to liferay portal. “No theme found for specified theme id .”
http://stackoverflow.com/questions/11721220/error-occures-when-deploying-theme-to-liferay-portal-no-theme-found-for-specif
[8] Techspace - No theme found for specified theme id abc_WAR_xyztheme
http://parasjain.net/2012/07/11/no-theme-found-for-specified-theme-id-abc_war_xyztheme/
[9] LiferaySavvy - List of Velocity Variables in Liferay
http://www.liferaysavvy.com/2015/02/list-of-velocity-variables-in-liferay.html
[10] Wikipedia - Apache Velocity
https://en.wikipedia.org/wiki/Apache_Velocity
[11] Liferay Company Blogs - Using jQuery (or any Javascript library) in Liferay 6.0
http://www.liferay.com/web/nathan.cavanaugh/blog/-/blogs/using-jquery-or-any-javascript-library-in-liferay-6-0

Friday, 19 September 2014

Maven and PlantUML

This blog explains about integrating PlantUML with Netbeans and Maven. For integrating PlantUML with Netbeans and Ant, see my previous blogpost here.

The blog at [2] explained to me how to add PlantUML to my Maven project, using the special plugin developed by jeluard1.

Just adding the following to the plugins did the trick:
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
    <groupId>com.github.jeluard</groupId>
    <artifactId>plantuml-maven-plugin</artifactId>
    <version>1.1</version>
    <configuration>
        <outputInSourceDirectory>false</outputInSourceDirectory>
        <outputDirectory>${basedir}/target/site/apidocs</outputDirectory>
        <sourceFiles>
            <directory>${basedir}/src/main/java/</directory>
            <includes>
                <include>**/*.java</include>
            </includes>
        </sourceFiles>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>net.sourceforge.plantuml</groupId>
            <artifactId>plantuml</artifactId>
            <version>8004</version>
        </dependency>
    </dependencies>
</plugin>

Netbeans and Maven

In Netbeans you can select Actions on your project to perform. There is a coupling between the action and the goals in Maven that are executed3.

These can be changed by going to your Netbeans Project Properties (right-click your project, select properties) - select "Actions" - select "Generate Javadoc".

Then add the plantuml Maven goal, com.github.jeluard:plantuml-maven-plugin:generate. You're likely to end up with the following:
generate-sources javadoc:javadoc com.github.jeluard:plantuml-maven-plugin:generate

References

[1] GitHub - jeluard/maven-plantuml-plugin
https://github.com/jeluard/maven-plantuml-plugin
[2] Smartics - Using PlantUML
http://www.smartics.de/archives/1313
[3] Netbeans - MavenBestPractices
http://wiki.netbeans.org/MavenBestPractices

Friday, 12 September 2014

Moving From Ant to Maven

My project "karchangame" is Ant-based, basically because when you create a new project in Netbeans, the Ant configuration is the default.

This has worked well for a long time, until I decided recently to upgrade some of the libraries that I use. Now, in Ant, you just download the libraries you need and put the jar-files in your classpath.

That works fine if your libraries are not complicated. But I noticed that some of my libraries are now dependant on yet other libraries.

In short, I just spent an hour in getting the libraries I need, then getting the required libraries of those libraries, ad infinitum.

Maven takes care of this whole slog, by putting the responsibility for defining the required libraries for a framework/library squarely on the shoulders of that framework/library.

What I was stuck with was finding the best way of changing my Ant-based project into a Maven-based project.

Moving from Ant to Maven


The easiest way that I could come up with is to create a brand new Maven-based project. The original was a Web Application, so the new Maven project should also be a Web Application. As far as I could tell every possibility for a new ant-based project is also available as a new maven-based project.

And then start moving files over to the appropriate place in the new Maven structure.

I really like the fact that Git actually detects these moves instead of like in the old days, when a move was an explicit delete and create of two non-related files, making you lose your entire history of that file.

The difference in the directory structure is as follows:
You do notice that Maven actually has a more layered structure, whereas Netbeans Ant basically dumps everything in the root.

So, the move basically entailed the following:
From antTo Maven
build.xmlpom.xml
-nb-configuration.xml
nbproject-
lib- (actually stored in your m2 repo)
src/confsrc/main/resources
src/javasrc/main/java
websrc/main/webapp
testsrc/test/java
buildtarget
dist/karchangame.wartarget/karchangame-1.0-SNAPSHOT.war

Pom.xml

I only needed to make a few changes to my pom.xml file, in order to get all the dependencies sorted out.

JMockit

Needed to add JMockit, or my testcode didn't compile.
<dependency>

    <groupId>org.jmockit</groupId>
    <artifactId>jmockit</artifactId>
    <version>1.10</version>
    <scope>test</scope>
</dependency>

AntiSamy

AntiSamy to prevent evil hackers from gaining access.
<dependency>
    <groupId>org.owasp.antisamy</groupId>
    <artifactId>antisamy</artifactId>
    <version>1.5.3</version>
</dependency>

URL Validation

<dependency>

    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.4.0</version>
</dependency>
It's amazing to see Maven automatically download all the required libraries.

The last part was adding plantuml back into the mix. But I'll talk about that in the next Blog.

References

Apache Maven
http://maven.apache.org/
Netbeans - MavenBestPractices
http://wiki.netbeans.org/MavenBestPractices