Monday, September 24, 2018

7 tools providing visibility for maven dependency tree

With maven pom.xml, you can have maven manage your project's dependency automatically. Whenever your project's code needs classes in a jar file, you can specify the dependency in your pom.xml, and give it a scope to specify whether this jars is needed for compile time, run time or test time. As long as the jars exist in maven repository, they will be downloaded into your local repository, which by default under ~/.m2/repository. Your project will include a set of jars which you specify in your pom.xml, they maps to the jar folders in ~/.m2/repository, and maven will include them in classpath. Those depended jars also has dependency specified in their own pom.xml. Maven goes one step further to download all the jars in the dependency chain, and have a set of rules to figure out which jar version takes precedence when it is declared in multiple places -- for example, when a jar version is declared in both parent pom and child pom, child pom takes precedence.

Enough theory about maven, here are 7 tools help you get visibility of maven dependency tree.
The example maven project used below can be checkout with "git clone https://github.com/GoogleCloudPlatform/appengine-gcs-client.git"

1. locate the dependency jar file. The groupId + artifactId + version in your pom.xml file is mapping to the corresponding directory. for example <groupId>org.codehaus.mojo</groupId> + <artifactId>versions-maven-plugin</artifactId> + <version>2.2</version> in the following example maps to ~/.m2/repository/org/codehaus/mojo/versions-maven-plugin/2.2/



>grep groupId pom.xml -A 2
    <groupId>com.google.appengine.tools</groupId>
    <artifactId>appengine-gcs-client-example</artifactId>

--
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-api-1.0-sdk</artifactId>
            <version>${appengine.version}</version>
--
            <groupId>com.google.appengine.tools</groupId>
            <artifactId>appengine-gcs-client</artifactId>
            <version>0.6</version>
--
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
--
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
--
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-api-stubs</artifactId>
            <version>${appengine.version}</version>
--
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>versions-maven-plugin</artifactId>
                <version>2.2</version>
--
                <groupId>org.apache.maven.plugins</groupId>
                <version>3.5.1</version>
                <artifactId>maven-compiler-plugin</artifactId>
--
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
--
                <groupId>com.google.appengine</groupId>
                <artifactId>appengine-maven-plugin</artifactId>
                <version>${appengine.version}</version>
--
              <groupId>com.google.appengine</groupId>
              <artifactId>gcloud-maven-plugin</artifactId>
              <version>${gcloud.plugin.version}</version>
>ls ~/.m2/repository/org/codehaus/mojo/versions-maven-plugin/2.2/
_remote.repositories versions-maven-plugin-2.2.jar versions-maven-plugin-2.2.pom
m2e-lastUpdated.properties versions-maven-plugin-2.2.jar.sha1 versions-maven-plugin-2.2.pom.sha1
>      

In eclipse, you can hold command key and click a dependency in your pom.xml to step into the dependency jar's pom.xml file which located in a folder under ~/.m2/repository.

2. display dependency tree. The command "mvn dependency:tree" will display the dependency hierarchy in a tree structure. For example, com.google.oauth-client:google-oauth-client:jar:1.21.0:compile is an indirect dependency introduced by com.google.appengine.tools:appengine-gcs-client:jar:0.6:compile in your pom.xml.


>mvn dependency:tree
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building appengine-gcs-client-example 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ appengine-gcs-client-example ---
[INFO] com.google.appengine.tools:appengine-gcs-client-example:war:1.0-SNAPSHOT
[INFO] +- com.google.appengine:appengine-api-1.0-sdk:jar:1.9.36:compile
[INFO] +- com.google.appengine.tools:appengine-gcs-client:jar:0.6:compile
[INFO] |  +- com.google.guava:guava:jar:19.0-rc1:compile
[INFO] |  +- joda-time:joda-time:jar:2.3:compile
[INFO] |  +- com.google.apis:google-api-services-storage:jar:v1-rev68-1.21.0:compile
[INFO] |  |  \- com.google.api-client:google-api-client:jar:1.21.0:compile
[INFO] |  |     \- com.google.oauth-client:google-oauth-client:jar:1.21.0:compile
[INFO] |  +- com.google.api-client:google-api-client-appengine:jar:1.25.0:compile (version selected from constraint [1.19,2.0))
[INFO] |  |  +- com.google.oauth-client:google-oauth-client-appengine:jar:1.25.0:compile
[INFO] |  |  |  \- com.google.oauth-client:google-oauth-client-servlet:jar:1.25.0:compile
[INFO] |  |  |     \- com.google.http-client:google-http-client-jdo:jar:1.25.0:compile
[INFO] |  |  +- com.google.api-client:google-api-client-servlet:jar:1.25.0:compile
[INFO] |  |  |  \- javax.jdo:jdo2-api:jar:2.3-eb:compile
[INFO] |  |  |     \- javax.transaction:transaction-api:jar:1.1:compile
[INFO] |  |  \- com.google.http-client:google-http-client-appengine:jar:1.25.0:compile
[INFO] |  +- com.google.http-client:google-http-client:jar:1.25.0:compile (version selected from constraint [1.19.0,2.0))
[INFO] |  |  +- com.google.code.findbugs:jsr305:jar:3.0.2:compile
[INFO] |  |  +- org.apache.httpcomponents:httpclient:jar:4.5.5:compile
[INFO] |  |  |  +- org.apache.httpcomponents:httpcore:jar:4.4.9:compile
[INFO] |  |  |  +- commons-logging:commons-logging:jar:1.2:compile
[INFO] |  |  |  \- commons-codec:commons-codec:jar:1.10:compile
[INFO] |  |  \- com.google.j2objc:j2objc-annotations:jar:1.1:compile
[INFO] |  \- com.google.http-client:google-http-client-jackson2:jar:1.25.0:compile (version selected from constraint [1.19,2.0))
[INFO] |     \- com.fasterxml.jackson.core:jackson-core:jar:2.9.6:compile
[INFO] +- javax.servlet:servlet-api:jar:2.5:provided
[INFO] +- jstl:jstl:jar:1.2:compile
[INFO] \- com.google.appengine:appengine-api-stubs:jar:1.9.36:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.037 s
[INFO] Finished at: 2018-09-24T21:19:12-04:00
[INFO] Final Memory: 17M/226M
[INFO] ------------------------------------------------------------------------
>

In eclipse, it is equivalent to the "Effective POM" tab's output.


The eclipse even goes one step further to list all the jar dependency chains in "Dependency Hierarchy" tab. Those needed but overruled jar versions are marked as "omitted for conflict".


3. you can force maven to download the source code for your jar files if they are available in maven remote repository. "mvn dependency:sources".

You can do the same in eclipse by right click a project -> Maven -> Download Sources


4. Sometimes you get a dependent jar that almost meets your requirement except some small dissatisfaction. You can check out the source code from svn, git, etc, modify the code, then issue "mvn install". This command will publish an artifact into your local repository. Other project want to use them can reference it with a dependency entry in pom.xml. For example, run "mvn clean install" for the example will create an artifact under .m2/repository/com/google/appengine/tools/appengine-gcs-client-example/1.0-SNAPSHOT/appengine-gcs-client-example-1.0-SNAPSHOT.pom, you can reference this artifact with

      <dependency>
            <groupId>com.google.appengine.tools</groupId>
            <artifactId>appengine-gcs-client-example</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>

        </dependency>

in other projects' pom.xml.

You can do the same in eclipse, by right clicking the project, then selecting Run as, then clicking Maven Install. Notice due to eclipse bug,  org.codehaus.mojo:versions-maven-plugin can not be executed, I comment it out to get the maven install running. It won't hurt main functionality, this plugin as the name says, is a nice to have step during compile.


5. You can build maven project with command line, then import the built project into eclipse or have eclipse synchronize with the update. To import an maven project in eclipse, you click File -> Import -> expand maven folder, select "Existing Maven Projects" -> click Next -> browse to the pom.xml you wan to import. To update maven project in eclipse, whenever you built maven project with command line, you right click the project, select maven then click "update project...". 

6. You can inspect exactly what jars your eclipse project has in the classpath, these jars are introduced by maven plugin. 



7. Finally, you resolved the dependency issue by specifying a particular dependent jar version to override the maven chosen version or adding a list of <exclusions><exclusion></exclusion>...</exclusions>  under some <dependency></dependency> to force maven to reconsider the version. Problem now solved, you can update the project versions to a higher one to mark this fix. You can change multiple pom.xml file versions with command "mvn versions:set -DnewVersion=1.3.x-SNAPSHOT. The versions:set goal will automatically climb up local directories to find the aggregation root. It will automatically update explicitly referenced dependencies.


Wednesday, September 5, 2018

7 useful google search syntax

We use google search all the time, mostly by typing a keyword into the search bar and press enter. This gives us lots of content, sometimes more than needed. With some constrain, we can narrow down the search.
  1. "java +xyzcode" this will search java, but the page must contains xyzcode, you can change + to - to indicate that the page must not contain xyzcode.
  2. "cache:xyzcode.blogspot.com" this will search google cached page history. As a blogger, if you saved something by mistake, don't panic, google has the backup. 
  3. "site:xyzcode.blogspot.com java" this will search java only on website xyzcode.blogspot.com
  4. "filetype:pom JGraphT" this will search JGraphT only in file type pom.
  5. "inurl:xyzcode" this will search xyzcode in the url itself.
  6. "xyzcode@facebook" this will search xyzcode in facebook.
  7. "#xyzcode" this will search hashtag xyzcode.

Sunday, September 2, 2018

how to setup ASUS HOME SERVER with mac os x

This is a small trick but will be handy if you need to access the ASUS HOME SERVER with system other than windows. The menu asked the user to install an windows application in order to access the server. However, notice the ASUS HOME SERVER are actually a reconfigured windows server 2003 with IIS server 6 up running. You can login it from you LAN with microsoft remote desktop.

Download and install microsoft remote desktop, configure the connection. You can find the ASUS HOME SERVER's LAN ip from your gateway router. The server generally don't response to LAN broadcast.

connect to windows server
connect to windows server


Double click the remote desktop icon to login, when ask for the administrator password, put the one you used to setup the server at the first place.

Once logged in, the windows home server console application is right there on the desktop, double click it, then you can configure the server as if you installed a windows access app. You will feel happy because this is actually a IIS server machine with windows server 2003 functionalities.

windows home server console
windows home server console

7 steps to allow you access your mac os x from internet

You can ssh into your home mac computer while traveling. There are a few steps to do:

step 1, go to system preferences, check sharing, check remote login. Only allow the unprivileged user to remote login, remove admin from the allowed list.

remote login enable
remote login enable


step 2. go to system preferences -> users & groups select the user you need to remote access the computer, change the password to be a very strong one.

step 3. if your firewall is blocking port 22, enable it. Go to system preferences -> Security and Privacy -> Firewall Options.

step 4. schedule wake up, if your computer go to sleep you won't be able to ssh into it. Go to system preferences -> Energy saver -> Schedule



schedule wakeup
schedule wakeup


step 5.  test remote login from LAN address, ssh <user>@<localIp>.

step 6. login your gateway router, add a port forwarding rule, forward port 22 to the ip address of your computer.

port forwarding
port forwarding


step 7. test remote login from internet address. The internet address can be found from gateway router.

You can disable password login and only allow certificate based login, but the above 7 steps should be able get your WAN access goal reached.

Why I stopped publishing blog posts as information provider

Now the AI can generate content. Does that mean the web publishing industry reaches the end? ChatGPT said: ChatGPT Not at all. While AI can ...