Archive for the 'java' Category

SSH with Java

Recently I needed to do some server manipulation over the SSH-2 protocol from a Java client program. There are quite a few choices of SSH libraries for Java out there. Usually I prefer BSD license whenever possible, so I thought I’ll give Ganymed SSH-2 for Java a try. It turned out to be pretty simple to use. Here’s a short example of how to connect to the server using the private key and execute some command.

import java.io.*;
import ch.ethz.ssh2.*;

public class Example {
  public static void main(String[] args) throws IOException {
    Connection conn = new Connection("hostname");
    conn.connect();
    File pemKeyFile = new File("privKey.pem");
    boolean isAuth = conn.authenticateWithPublicKey("user", pemKeyFile, "keyPwd");
    if (isAuth == false) {
      throw new IOException("Authentication failed.");
    }

    Session sess = conn.openSession();
    sess.execCommand("netstat -nl | egrep ':80' | wc -l");
    InputStream inp = sess.getStdout();
    InputStreamReader reader = new InputStreamReader(inp);
    BufferedReader br = new BufferedReader(reader);
    String line = br.readLine();

    sess.close();
    conn.close();
  }
}

If you’re unfamiliar with private/public key authentication over SSH, see the links below or just google for “passwordless ssh login”.

One thing that most tutorials don’t mention is that your home directory should have permissions 755. I found out through trial and error, that using some user’s home directory with permissions 777 just doesn’t let you login with a private key.

Another thing that I needed to do was copy a file over to the server. Now this gave me some unexpected problems. While the API seemed simple enough, the code below just didn’t work.

  String data = "sample data";
  SFTPv3Client client = new SFTPv3Client(conn);
  SFTPv3FileHandle handle = client.createFile("test_file.txt");

  byte []arr = data.getBytes();
  client.write(handle, 0, arr, 0, arr.length);
  client.closeFile(handle);
  client.close();

Here, the conn object is the SSH connection which can be acquired as shown in the first code listing. This looks  pretty straightforward – create a file on the server, write some bytes to it, then close, but the outcome of it all – the file is created on the server, but it is  always 0 bytes in length.  It took me a while to figure out what’s wrong. Now is the time to mention that I was using the “latest version” of Ganymed that was available on their page – build210. And this screwed me good. After I got frustrated with the code not working the way I wanted it to, I started looking through the source of Ganymed and I found an unsatisfiable conditional statement in the write(…) method of the SFTPv3Client class. I fixed the problem, recompiled Ganymed library and voila it works. Then later I found out that Ganymed actually has a release build211, but they renamed the library to trilead. You can find it in this maven2 repository.

iBatis and Stored Oracle procedures/functions

This one took me a while to get it right the first time. I won’t go into details of configuring iBatis datasources and such, and will go straight to putting some queries in the sqlMap file. Just let me note that I’m using iBatis 2.3 for these examples. I’ll start off with a procedure call.

<procedure id="getUserRoles" parameterMap="myParamMap">
    { call SCHEMA.GET_USERS_ROLES(?, ?) }
</procedure>

This one is pretty self-explanatory, just defining a procedure to be called. Notice the questionmarks in the SQL, don’t put the usual #variable# style annotation here. Also instead of parameterClass I use parameterMap here, which means I’ll have to define a parameter map for this query or it won’t work.

<parameterMap id="myParamMap" class="java.util.Map">
    <parameter property="username" mode="IN" />
    <parameter property="roles" jdbcType="ORACLECURSOR" mode="OUT" />
</parameterMap>

Here I explain to iBatis what kind of parameters I want to pass to the query and whether IN, OUT or INOUT mode should be used. It is important to specify correct jdbcType and javaType for the parameters otherwise when calling the procedure iBatis will spit out a very annoying Exception. Now for the JAVA part.

HashMap params = new HashMap();
params.put("username", username);
getSqlMapClient().queryForObject("getUserRoles", params);

Object o = params.get("roles");
if(o instanceof ResultSet)
{
    ResultSet res = (ResultSet) o;
    while(res.next())
        System.out.println(res.getInt("ROLE_NR"));
    res.close();
}

As you can see the procedure call is pretty much like any other SELECT query, but you don’t need to check the return value. All the OUT parameters will be stored in the Map object that you passed. In my case I defined a roles parameter as ORACLECURSOR which translates into ResultSet object. It’s not shown in this code snippet, but don’t forget to use startTransaction() and endTransaction() if you’re managing your own transactions. Also if the stored procedure is modifying the data you’ll most likely need commitTransaction() too, but iBatis transaction management is a different story.

And now for some stored function calling.

<procedure id="exampleFunction" parameterMap="funcMap">
    { ? = call SCHEMA.MY_FUNCTION(?, ?) }
</procedure>

The first thing you might notice is that it still says <procedure>, but it’s no a typo, iBatis doesn’t have a <function> tag (at least to my knowledge). Note how because it’s a function it has a questionmark at the beginning of the query to specify the return variable.

<parameterMap id="funcMap" class="java.util.Map">
  <parameter property="result" jdbcType="NUMERIC" mode="OUT"/>
  <parameter property="P1" />
  <parameter property="P2" javaType="java.util.Date" jdbcType="DATE" mode="OUT" />
</parameterMap>

Here I defined a parameter map which is pretty much like the one used for the procedure call except for the extra parameter result that is used to get the return value, but formally registered as an OUT parameter and not a return value.

HashMap params = new HashMap();
params.put("P1", param);
getSqlMapClient().queryForObject("exampleFunction", params);

Object o = params.get("result");
if(o instanceof Long)
{
    long res = (Long)o;
    System.out.println(res);
}

The actual call to the stored function is exactly the same as in the case of procedure. You just have to correctly configure the parameter mapping so that the return value will be available as an extra output parameter. In fact correctly configuring the parameter map was the place where I spent most of my time trying to figure out how to do it. In my case when using Oracle and retrieving an integer you can not jdbcType it INTEGER, NUMBER or whatever, it only worked when I put NUMERIC as a parameter JDBC type. That’s why I put so much stress on the parameter configuration. I wasted quite some time getting the annoying “java.sql.SQLException: Invalid column type” error. So, I guess that’s about it.

Certificate Generation with Java Tools

Java has a useful tool for generating private-public key pair, it’s called keytool and is located in your jdk/bin directory. Here’s a command line that I often use to generate keys and self-signed certificates for testing.

keytool -genkey -keyalg RSA -validity 365 -alias MyKey -keystore new_keystore.jks
-dname "CN=SubjectName, OU=My Department, O=My Company, L=Vilnius, S=Vilnius, C=LT"

Also it is sometimes needed to generate a request to get a signed certificate. Having created a keystore as shown above, it is easily done with the following line.

keytool -certreq -alias MyKey -keyalg RSA -keysize 2048 -file myfile.csr -keystore
new_keystore.jks

I realize that this is pretty trivial, but it’s nice to have it written down in case I forget something :)

Using maven

Maven is an awesome build tool for JAVA, but it has some long parameter names that I don’t like to remember, so I put my often used tasks of maven in batch files.

install.bat

mvn install:install-file -Dfile=%1 -DgroupId=%2 -DartifactId=%3
-Dversion=%4 -Dpackaging=pom -DgeneratePom=true

This installs the specified .jar file in the local repository located in

C:\Documents and Settings\*User*\.m2\repository

where *User* is your username. Four arguments are required: jar_file, group, artifact and version.

new.bat

mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes
-DgroupId=%1 -DartifactId=%2

I use this one to create new projects for stand-alone java programs. Two arguments required: group and artifact.

webnew.bat

mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes
-DarchetypeArtifactId=maven-archetype-webapp -DgroupId=%1 -DartifactId=%2

This one creates a new project for a web application. Two arguments required: group and artifact.

More maven commands

  • mvn idea:idea – generate IDEA project files
  • mvn eclipse:eclipse – generate Eclipse project files
  • mvn clean package – clean target directory, rebuild and package
  • mvn jboss:deploy – deploy project to local jboss instance
  • mvn jboss:undeploy – undeploy project from local jboss instance

pom.xml

  <build>
    <finalName>myProject</finalName>
    <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <source>1.5</source>
        <target>1.5</target>
        <encoding>utf-8</encoding>
      </configuration>
    </plugin>
    </plugins>
  </build>

This is a snipet from pom.xml (maven configuration) file that I often add after creating a new project.

Ant tasks in pom.xml

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
    <dependencies>
      <dependency>
        <groupId>ant</groupId>
        <artifactId>ant-antlr</artifactId>
        <version>1.6.5</version>
      </dependency>
    </dependencies>
    <configuration>
      <!-- put Ant tasks here -->
    </configuration>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>run</goal>
        </goals>
      </execution>
    </executions>
</plugin>

This is very useful when you have some specific tasks that you were using in Ant and you don’t know the maven equivalent or if they’re custom made.

This is just a short compilation of things that I do with maven on a regular basis. There’s a lot more to this tool than shown here, and I’m still learning it myself. You can get more information on how to get started with maven here.


 

January 2010
M T W T F S S
« Nov    
 123
45678910
11121314151617
18192021222324
25262728293031