Saturday, February 25, 2017

Publishing to Maven Central

I couldn't find any coherent guides for publishing to Maven Central, so here's my somewhat incoherent guide.

Account Setup


The first step is to request an account from Sonatype, via Jira. This is described under initial setup

This can take a few days since a human needs to evaluate the request, for example to verify you own the domain of the groupId.

Save jira username/password credentials

Configuration


Install gpg

brew install gpg
brew install gpg-agent

I got the following error, apparently related to upgrading to mac sierra

Error: The following formula:
gpg-agent
cannot be installed as a binary package and must be built from source.

Create a key with gpg gen-key
Save your passphrase somewhere safe, like keypass

gpg --list-keys
/Users/andrew/.gnupg/pubring.gpg
--------------------------------
pub   4096R/1BC87E06 2017-01-07
uid                  Andrew Rapp
sub   4096R/C654CD46 2017-01-07

Send your pub key to key servers
$ gpg --keyserver hkp://pool.sks-keyservers.net --send-keys 1BC87E06

Now add the maven publishing configuration to your pom.xml

This is somewhat documented here
Update maven settings ( ~/.m2/settings.xml):

<settings>
<servers>
<server>
  <id>ossrh</id>
  <username></username><!-- sonatype jira account -->
  <password></password><!-- jira password -->
</server>
</servers>
<profiles>
<profile>
<id>gpg-profile</id>
<properties>
  <gpg.useagent>true</gpg.useagent>
</properties>
</profile>
</settings>

Publishing


Run gpg-agent so we don’t need to put the passphrase in mvn config

eval $(gpg-agent --daemon --no-grab --write-env-file $HOME/.gpg-agent-info)
export GPG_TTY=$(tty)
export GPG_AGENT_INFO

Release a Snapshot


Set the Maven version in the pom.xml to -SNAPSHOT. You can use maven for this:

mvn versions:set -DnewVersion=0.9.1-SNAPSHOT

export JAVA_HOME=`/usr/libexec/java_home -v 1.6` && mvn clean deploy

If you’re not concerned with the version of Java then skp the JAVA_HOME export

You should get prompted for your gpg passphrase

Login to https://oss.sonatype.org/#view-repositories and search for your groupid

Snapshots
For Releases

Release a Final Version


Update version in pom.xml

mvn versions:set -DnewVersion=0.9.1

NOTE: If in pom.xml autoReleaseAfterClose is true it will release after deploy. Otherwise will go to staging area and will need to be released manually

export JAVA_HOME=`/usr/libexec/java_home -v 1.6` &&  mvn clean deploy -P release

Alternatively you can release via the sonatype Nexus Repository Manager https://oss.sonatype.org/#welcome

It can take hours for the artifact to land on maven central.

Be sure to remove the artifacts from your local repo ~/.m2 if you want to be sure to pull from maven central version

Tag the release and push to git

git tag with release, e.g. git tag v0.9.1
git push origin master --tags

Now rev the pom version to the next SNAPSHOT version, e.g.

mvn versions:set -DnewVersion=0.9.2-SNAPSHOT

And if I misled you, this guide looks pretty good

http://www.ryanchapin.com/fv-b-4-783/How-To-Distributed-Artifacts-in-the-Maven-Central-Repository.html

pom.xml


<groupId>com.rapplogic</groupId>
<artifactId>xbee-api</artifactId>
<packaging>jar</packaging>
<version>0.9.4-SNAPSHOT</version>

<name>${project.groupId}:${project.artifactId}</name>
<description>A java library for communicating with XBee radios</description>
<url>https://github.com/andrewrapp/xbee-api/</url>

<licenses>
   <license>
      <name>GPL license, Version 3.0</name>
      <url>https://www.gnu.org/licenses/gpl-3.0.html</url>
   </license>
</licenses>

<developers>
   <developer>
      <name>Andrew Rapp</name>
      <email></email>
   </developer>
</developers>

<scm>
   <connection>scm:git:git@github.com:andrewrapp/xbee-api.git</connection>
   <developerConnection>scm:git:git@github.com:andrewrapp/xbee-api.git</developerConnection>
   <url>https://github.com/andrewrapp/xbee-api/</url>
</scm>

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <maven.compiler.source>1.6</maven.compiler.source>
   <maven.compiler.target>1.6</maven.compiler.target>
</properties>

<distributionManagement>
   <snapshotRepository>
      <id>ossrh</id>
      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
   </snapshotRepository>
   <repository>
      <id>ossrh</id>
      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
   </repository>
</distributionManagement>

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

      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-gpg-plugin</artifactId>
         <executions>
            <execution>
               <id>sign-artifacts</id>
               <phase>deploy</phase>
               <goals>
                  <goal>sign</goal>
               </goals>
            </execution>
         </executions>
      </plugin>

      <plugin>
         <groupId>org.sonatype.plugins</groupId>
         <artifactId>nexus-staging-maven-plugin</artifactId>
         <version>1.6.7</version>
         <extensions>true</extensions>
         <configuration>
            <serverId>ossrh</serverId>
            <nexusUrl>https://oss.sonatype.org/</nexusUrl>
            <autoReleaseAfterClose>true</autoReleaseAfterClose> <!-- if true does what you think; otherwise need to release via sonatype UI -->         </configuration>
      </plugin>

      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-source-plugin</artifactId>
         <executions>
            <execution>
               <id>attach-sources</id>
               <goals>
                  <goal>jar</goal>
               </goals>
            </execution>
         </executions>
      </plugin>

      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
         <executions>
            <execution>
               <id>attach-javadocs</id>
               <goals>
                  <goal>jar</goal>
               </goals>
            </execution>
         </executions>
         <configuration>
            <!--mvn 3.3.9: Exit code: 1 - javadoc: error - invalid flag: -Xdoclint:none-->            <!-- need the following or fails on: get self-closing element not allowed -->            <additionalparam>-Xdoclint:none</additionalparam>
         </configuration>
      </plugin>
   </plugins>
</build>

Thursday, February 23, 2017

Restarting a Server From a Web Service


Often times you may want a simple web service call to restart your server. There is a problem however if the web service is running in the application to be restarted. You can't simply call a restart script from your application, at least in Java, since Java needs to die to complete the call, and this would kill the restart process along with it. To overcome this limitation you can wrap the restart script in a nohup and background it.

Create nohup-restart.sh, containing the following:

nohup ./bin/restart.sh $1 > restart.out 2> restart.err &

Then create restart.sh, containing:

sleep 3
kill $1
app.sh

The sleep is to give the web service time to respond before it shuts down.

You can pass the pid from Java into the script. The pid is accessed by

ManagementFactory.getRuntimeMXBean().getName()

But strip out the @machine part).

Now call Runtime.exec with fully qualified path to script. Depending on how it was started you might be able to get away with a path relative to user.dir.

process = Runtime.getRuntime().exec(new String[] {scriptPath, "nohup-restart.sh", ManagementFactory.getRuntimeMXBean().getName().split("@")[0]});

If the script is daemon it's much simpler since it can be called without the nohup nonsense, however it should be called in a Thread to give it time to respond.