Maven起動時のエラー

Mavenの起動時にエラーが出たのでメモ

エラーメッセージ

$ mvn package
メイン・クラスorg.codehaus.plexus.classworlds.launcher.Launcherが見つからなかったかロードできませんでした

対応方法

こちらを参考に

$ unset M2_HOME
$ mvn package

omp4jによる並列化

Pythonで並列化させたプログラムを走らせていたのですがあまりの遅さにJavaへと変更した際、並列化をomp4jで簡単にできたのでメモ。

omp4j

OpenMPの説明は、Wikipediaをみてもらうことにして、ソースコード中にコメントを書いておいて、コンパイルをすれば並列化プログラムの出来上がるという便利なライブラリ。

ここからJarファイルをダウンロードします。

wget https://github.com/omp4j/omp4j/releases/download/v1.2/omp4j-1.2.jar

Javaプログラム

簡単なプログラムを作成します。スレッド5で10回計算しています。


import java.util.Random;


public class OmpTest {
        private void run() {
                try {
                        // omp parallel for threadNum(5)
                        for (int i = 0; i < 10; i++) {
                                new Task1(i).call();
                        }

                } finally {
                        System.out.println("ThreadTest:finish");

                }
        }

        static class Task1{
                private int number;
                Task1(int number){
                        this.number=number;

                }
                public Long call()  {
                        System.out.println("Task1.start:"+this.number);
                        long sleep=new Random().nextInt(10)*1000;
                        long sum = 0;
                        for (int i = 1; i <= 100 * 10000; i++) {
                                sum += i;
                        }
                        try{
                                Thread.sleep(sleep);
                        }catch(Exception e){}
                        System.out.println("Task1.end:"+this.number+",sleep="+sleep);
                        return sum;
                }
        }

        public static void main(String[] argv){
                new OmpTest().run();
        }
}

シングルスレッド

普通にコンパイルします。シングルスレッドで動作します。


$ javac OmpTest.java
$ java OmpTest
Task1.start:0
Task1.end:0,sleep=3000
Task1.start:1
Task1.end:1,sleep=2000
Task1.start:2
Task1.end:2,sleep=1000
Task1.start:3
Task1.end:3,sleep=0
Task1.start:4
Task1.end:4,sleep=5000
Task1.start:5
Task1.end:5,sleep=6000
Task1.start:6
Task1.end:6,sleep=9000
Task1.start:7
Task1.end:7,sleep=3000
Task1.start:8
Task1.end:8,sleep=8000
Task1.start:9
Task1.end:9,sleep=2000
ThreadTest:finish

シリアルに計算されているのがわかります。

マルチスレッド

並列化できるようにコンパイルします。


$ java -jar omp4j-1.2.jar OmpTest.java
$ java OmpTest
Task1.start:3
Task1.start:1
Task1.start:2
Task1.start:4
Task1.start:0
Task1.end:1,sleep=0
Task1.start:5
Task1.end:0,sleep=3000
Task1.start:6
Task1.end:2,sleep=3000
Task1.end:5,sleep=3000
Task1.start:7
Task1.start:8
Task1.end:3,sleep=4000
Task1.start:9
Task1.end:4,sleep=7000
Task1.end:9,sleep=3000
Task1.end:6,sleep=8000
Task1.end:8,sleep=8000
Task1.end:7,sleep=9000
ThreadTest:finish

並列に計算できているのがわかります。
実際にはコンパイル時にコードを変換してコンパイルしています。
ここにソースコードを貼り付けると変換後のソースが表示されます。上記サンプルだとエラーになってしまいましたが、簡単なコードならばそのコードが表示されます。

まとめ

簡単にJavaのコードが並列化できます。色々と制約はありますが(変数関連など)、簡単に並列プログラムが作成できるのはメリットでしょう。

AmazonS3にjavaSDKを用いて文字列を書き込む

ポイントは2回InputStreamを作成することです。

http://stackoverflow.com/questions/8351886/amazons3-putobject-with-inputstream-length-example

package awssample;

import java.io.ByteArrayInputStream;

import java.io.InputStream;

import java.sql.SQLException;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.util.IOUtils;

public class S3Write {

	private static String endpoint = "https://s3-ap-northeast-1.amazonaws.com";

	public static void main(String[] args) throws SQLException {

		String s = "2011-01-01,9999,1,100,1.0,-1.0,0.5";
		// 認証オブジェクトを作成
		String accessKey = "xxxxxx";
		String accessSecretKey = "xxxxxxxx";
		AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecretKey);

		// ConfigurationでTimeout時間を30秒に設定
		ClientConfiguration clientConfiguration = new ClientConfiguration();
		clientConfiguration.setConnectionTimeout(30000);

		// AmazonS3Clientをインスタンス化
		AmazonS3Client s3 = new AmazonS3Client(credentials, clientConfiguration);
		s3.setEndpoint(endpoint);
		try {
			InputStream is = new ByteArrayInputStream(s.getBytes("UTF-8"));
			byte[] contentBytes = IOUtils.toByteArray(is);
			Long contentLength = Long.valueOf(contentBytes.length);
			System.out.println("contentLength=" + contentLength + ",s=" + s);

			ObjectMetadata metadata = new ObjectMetadata();
			metadata.setContentLength(contentLength);
											 // isではなく new ByteStreamInputStreamでもう一度さくせいしたものを渡す
			s3.putObject(new PutObjectRequest("bucketname", "path/to/file.txt",
					new ByteArrayInputStream(s.getBytes("UTF-8")), metadata));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

JD-Eclipseのインストールではまった

ちょっと以前まではEclipseの逆コンパイラ、JD-EclipseのインストールにはUpdateサイトから行っていたのですが、Lunaでインストールした際にはまったので以下にメモ。

  • OS MacOSX 10.10
  • Eclipse 4.4 luna
  • Java 8

http://totech.hateblo.jp/entry/2015/02/19/145004

こちらに書いてあるようにhttp://jd.benow.ca/jd-eclipse/updateのupdateサイトをHelpのInstallNewSoftwareからインストールするとJD-Eclipseの0.1.5というバージョンがインストールされます

これを使用し、デコンパイルしようとしてもうまくデコンパイルされません。最初はFileassociationがおかしいのか?と思い設定を見直したのですがClassFileEditorのまま、特におかしなところはありません。

ずいぶん悩んだのですが、JD-Eclipseのサイトに書いてある手順がファイルからインストールしろとのことなのでその通りにします

https://github.com/java-decompiler/jd-eclipse

こちらからjd-eclipse-site-1.0.0-RC2.zipをダウンロード

https://github.com/java-decompiler/jd-eclipse/releases

EclipseのヘルプーInstallNewSoftwareのAddからArchiveを選択、先ほどのZIPファイルを選択しインストール。

インストールすると1.0.0のバージョンがインストールされます。

FileAssociationもJD Class FileViewerとなります。

これでclassファイルを選択するとめでたく逆コンパイルされます。

古いバージョンのJD-EclipseはJava8には対応していないのでしょうか。。

eclipseでTomcatの設定

いつも忘れてしまうのでメモ

環境

MacOS10.9
tomcat7

brew install tomcat7

java

oracle jdkをインストールし、シンボリックリンク

$ which java

/Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home//bin/java

eclipse kepler

インストール

EclipseのClassicをインストールするとサーバランタイムがインストールされずに、TOMCATアプリなど作成する際にデバッグに困ってしまいます。

サーバランタイムをインストールするには、予めBrewでTomcatをインストールした後に、ヘルプのinstall new softwareから

http://download.eclipse.org/releases/kepler

を選択し、いかの2つのプラグインをインストールします。

  • JST Server Adapters
  • JST Server Adapters Extensions

その後、環境設定ーServerーRuntimeEnvironmentsのaddでtomcatを追加するのですが、この際にディレクトリに以下を入力します

/usr/local/Cellar/tomcat7/7.0.55/libexec

これでサーバランタイムが設定可能となります。

この辺りの内容はこちらから引用しています

http://stackoverflow.com/questions/2000078/apache-tomcat-not-showing-in-eclipse-server-runtime-environments

http://stackoverflow.com/questions/17745834/unknown-version-of-tomcat-was-specified-with-tomcat-7-0-42

SQLiteにユーザ定義関数を追加しTOMCAT+DBCPで利用する

ユーザ定義関数の追加

SQLiteにはストアドプロシージャはなく、その代わりにユーザ定義関数を追加し、同様の処理を行うようにできます。


	
	public class TestFunc extends Function{
		@Override
		protected void xFunc() throws SQLException
		{
			try{
				String a = value_text(0);
				String b = value_text(1);
				result(Integer.parseInt(a)+Integer.parseInt(b));
			}catch(Exception e){
				throw new SQLException(e.getMessage());
			}
		}
	}

org.sqlite.Functionを継承したクラスを作成し、その中のxFuncをオーバラードしたメソッで実装する関数を定義しresultで戻します。

今回の場合には文字列で定義した数字を足しあわせて返すという関数を定義しました。

これを利用する際にはJDBCのコネクションに対しFunction.createでバインドしてやります


			InitialContext ic = new InitialContext();
			DataSource ds = (DataSource)ic.lookup("java:comp/env/test");
			Connection conn=ds.getConnection();
			conn.setAutoCommit(false);
			Function.create(conn,"my_func",new TestFunc());
	
			PreparedStatement stmt=conn.prepareStatement("select my_func(?,?)");
			stmt.setString(1,"1");
			stmt.setString(2,"3");
			ResultSet rs=stmt.executeQuery();
			while(rs.next()){
				out.println(rs.getString(1));
			}

バインドする際にSQL文内で呼ぶ関数名を同時に定義します。その後は通常のJDBCの処理と同じです。

DBCPで使う

DBCPで使うサンプルです

  • context.xml
				 	
  • TestServlet.java
public class TestServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	
	@Override
	public void init(ServletConfig sc) throws ServletException {
		super.init(sc);
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		doPost(req, res);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		res.setContentType("text/html;charset=utf-8");
		PrintWriter out=res.getWriter();
		
		//http://stackoverflow.com/questions/6489514/apache-commons-dbcp-connection-object-problem-thread-classcastexception-in-org
		//http://www.ksky.ne.jp/~snbhsmt/commons-dbcp.html
		//http://grokbase.com/t/tomcat/users/052spdat5s/tomcat-5-5-7-using-builtin-jdbc-connection-pool-cant-access-real-connection-accesstounderlyingconnectionallowed-true
		try{
			
			InitialContext ic = new InitialContext();

			BasicDataSource ds = (BasicDataSource)ic.lookup("java:comp/env/test");
								//ds.setAccessToUnderlyingConnectionAllowed(true);
								DelegatingConnection dcon=(DelegatingConnection)ds.getConnection();
			
								DelegatingStatement dstmt = (DelegatingStatement)dcon.createStatement();
								PoolableConnection pconn=(PoolableConnection)dstmt.getDelegate().getConnection();

								Connection conn=pconn.getInnermostDelegate();
			conn.setAutoCommit(false);
			Function.create(conn,"my_func",new TestFunc());
	
			PreparedStatement stmt=conn.prepareStatement("select my_func(?,?)");
			stmt.setString(1,"1");
			stmt.setString(2,"3");
			ResultSet rs=stmt.executeQuery();
			while(rs.next()){
				out.println(rs.getString(1));
			}
			dcon.close();// 140916 閉じ忘れるとTOMCAT起動時に止まる
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	public class TestFunc extends Function{
		@Override
		protected void xFunc() throws SQLException
		{
			try{
				String a = value_text(0);
				String b = value_text(1);
				result(Integer.parseInt(a)+Integer.parseInt(b));
			}catch(Exception e){
				throw new SQLException(e.getMessage());
			}
		}
	}
}

ここでのポイントはDBCPのコネクションプールからJDBCのコネクションを取得する際に実際のコネクションを取得してやる必要があります。

			BasicDataSource ds = (BasicDataSource)ic.lookup("java:comp/env/test");
						//ds.setAccessToUnderlyingConnectionAllowed(true);
						DelegatingConnection dcon=(DelegatingConnection)ds.getConnection();
			
						DelegatingStatement dstmt = (DelegatingStatement)dcon.createStatement();
						PoolableConnection pconn=(PoolableConnection)dstmt.getDelegate().getConnection();

						Connection conn=pconn.getInnermostDelegate();

この部分です。詳細は↓あたりを参考にしてください。

http://stackoverflow.com/questions/6489514/apache-commons-dbcp-connection-object-problem-thread-classcastexception-in-org

http://www.ksky.ne.jp/~snbhsmt/commons-dbcp.html

http://grokbase.com/t/tomcat/users/052spdat5s/tomcat-5-5-7-using-builtin-jdbc-connection-pool-cant-access-real-connection-accesstounderlyingconnectionallowed-true

なおJDBCはsqlite-jdbc-3.7.2.jarではなくsqlite-jdbc-3.8.5-pre1.jarを使用してください。Function.create内のinstanceofでconnectionが実コネクションかどうか判定しているのですが、JDBCが古いほうだと何故かここでエラーになってしまいます。

こんな感じでSQLite+DBCPでユーザ定義関数が追加できます。参考になれば幸いです

20140916追記

DelegateingConnectionを取得した際にコネクションを閉じ忘れるとTOMCAT起動時にエラーというか無限ループに陥ります。注意

StringからEnumの作成

文字列からEnum型へ変換するサンプルです

public class test{ 
 
	public static enum Channel{PC,WEB; 
		static Channel get(String s){ 
			Channel[] channels=Channel.values(); 
			for(Channel channel:channels){ 
				if(channel.toString().equals(s))return channel; 
			} 
			return null; 
		} 
}; 
 
	public static void main(String[] argv){ 
		System.out.println(Channel.WEB); // Enumをそのまま出力
		System.out.println(Channel.get("PC")); // 文字列からEnumを取得してみる
	} 
} 

Mahoutでjava.util.NoSuchElementExceptionが出た時の対処

機械学習用のライブラリ、ApacheMahoutを使用していてちょっと困ったのでメモ

import java.io.*;
import java.util.*;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.recommender.*;
import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.similarity.ItemSimilarity;

class test{

	public static void main(String[] argv){
		try{
			DataModel model=new FileDataModel(new File("test.csv"));
			ItemSimilarity similarity=new PearsonCorrelationSimilarity(model);
			Recommender recommender= new GenericItemBasedRecommender(model,similarity);
			List recommendations=recommender.recommend(1,5);
			for(RecommendedItem recommendation:recommendations){
				long recommendCode=recommendation.getItemID();
				System.out.println(recommendCode);
			}
		}catch(Exception e){}
	}
}

こんなかんじでアイテムベースのレコメンドを作成していたのですが、CSVファイルを読み込んだ際に

java.util.NoSuchElementException
				at com.google.common.base.AbstractIterator.next(AbstractIterator.java:75)
				at org.apache.mahout.cf.taste.impl.model.file.FileDataModel.processLine(FileDataModel.java:384)
				at org.apache.mahout.cf.taste.impl.model.file.FileDataModel.processFile(FileDataModel.java:340)
				at org.apache.mahout.cf.taste.impl.model.file.FileDataModel.buildModel(FileDataModel.java:239)
				at org.apache.mahout.cf.taste.impl.model.file.FileDataModel.reload(FileDataModel.java:208)
				at org.apache.mahout.cf.taste.impl.model.file.FileDataModel.(FileDataModel.java:194)
				at org.apache.mahout.cf.taste.impl.model.file.FileDataModel.(FileDataModel.java:149)

こんなエラーが出て進まない時がある。実行したのはLinux64Bit環境のjdk1.6。

同じものをwindows7のjdk1.6で動かしてもエラーが出ない。。。

読み込んだCSVは600万行程度

よくわからないのですがCSVの最後に改行を入れるとエラーなく動作。

わけわからん

Javaで自ホストのIPアドレスで127.0.0.1以外を取得する

ちょっと困ったのでメモ

通常JavaのInetAddress.getLocalHost().getHostAddress()から取得できるIPアドレスは127.0.0.1

これではちょっと使えません

ネットワークインターフェースを調べるとちゃんとした?IPアドレスが取得できます

import java.net.*;
import java.util.*;


public class test{
	public static void main(String[] argv)throws Exception{
		Enumeration n = NetworkInterface.getNetworkInterfaces();
			while (n.hasMoreElements()){
				NetworkInterface e = n.nextElement();
				Enumeration a = e.getInetAddresses();
				while ( a.hasMoreElements()){
					InetAddress addr = a.nextElement();
																		if (!addr.getHostAddress().equals("127.0.0.1"))
							 System.out.println(addr.getHostAddress());
				}
		 }
	}
}

eclipse+tomcatでアクセスログの場所

意外とわからなかったのでメモ。

環境

  • eclipse kelpher
  • tomcat 7
  • java 7

手順

  1. プロジェクトの作成でWebーDynamicWebで作成
  2. Eclipseの環境設定のServer、RuntimeEnvironmentsにtomcat 追加
  3. プロジェクトのpropertiesからjava build pathのLibrariesにadd LibrariesからServer Runtime のTOMCATを追加
  4. なんか作成
  5. Debug AsのDebug ConfigurationからTomcatのargumentsを確認
  6. ここの-Dcatalina.baseのパス以下にTOMCATのいろいろなものが入っている(/Users/username/Documents/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0)
  7. このlogs以下にアクセスログが作成される