NetBeans + AngularJs (windows)

環境準備のうる覚え

プロジェクト作成

新規プロジェクト > HTML5 > HTML5アプリケーション > プロジェクト名決める > オンラインテンプレート「AngularJs」

npm

生成されたプロジェクト右クリ > npmインストール > エラー発生 > https://nodejs.org/download/ からDL&インスコ

netbeansを右クリで「管理者として実行」で開くと何かとうまくいった

bower

生成されたプロジェクト右クリ > bowerインストール > エラー発生(bower html5-boilerplate#~4.3.0 ENOGIT git is not installed or not in the PATH) > git bashインスコ > gitのパスをPathを2つ追加(C:\Program Files (x86)\Git\bin;C:\Program Files (x86)\Git\cmd)

netbeansを右クリで「管理者として実行」で開くと何かとうまくいった


npmとbowerのインスコがうまくいくとプロジェクトが赤字から黒字になる。
サンプル動かすしても、エラー系のログがでなくなった。

java.io.NotSerializableException

問題

java.io.NotSerializableException

とあるオブジェクトをこのtoByte()でbyteに変換しようとしたらエラーがでた。
Javaで大量データをメモリに展開するテクニックの考察 - Symfoware

解決方法

java.io.NotSerializableException - How to solve Not Serializable Exception | Examples Java Code Geeks

import java.io.Serializable;

public class TransientExample implements Serializable {
	private static final long serialVersionUID = 6128016096756071380L;
	private transient Pair pair = null;
	
	public TransientExample(String key, Integer value) {
		this.pair = new Pair(key, value);
	}
	
	@Override
	public String toString() {
		return pair.toString();
	}
}

適当なクラスを作って、
・implements Serializableつける
・問題のあるクラスをtransient で定義しなおす
でエラーきえた。

~~~
あれ、逆か。transientは不要っぽい。

それと、そもそもOAuthConsumerをSerializeしようとしていてエラーが発生したのがきっかけだが、少し複雑な感じ。
結論からいくと、OAuthConsumerはサーバ側で保持する必要はなく、Providerだけ保持していればいいっぽい。
Issue 11 - oauth-signpost - Make OAuthProvider and OAuthConsumer serializable - Simple OAuth message signing for Java - Google Project Hosting


そして、OAuthConsumerはnewで初期化した時点ではserialize可能だが、たぶんproviderと混ぜてURL生成なんかをしていると、途中からserializeできなくなる。(しようとするとnullが返された。serializeするライブラリによってはエラーを吐く)

url = provider.retrieveRequestToken(consumer, callback);

~~~
最終的にうまくいったのでまとめ。

oauthの各ステップ

  • STEP01:認証URLの生成
    • consumerとproviderを初期化
    • sessionやDBとかでproviderは保持しておく
    • consumerが持っているaccessTokenKeyとSecペアをsessionやDBで保持しておく(これがわかりにくかった)
  • STEP02:認証ページからのCALLBACK
    • callback先に認証キーがGETパラメータで返ってくるので、それをsessionとかDBで保持しておく
  • STEP03:利用
    • providerは保持しておいたやつをそのまま使う
    • consumerはSTEP01と同様に初期化した後、STEP01で保持しておいたaccessTokenKeyとSecをconsumerに適用する(これがわかりにくかった)
    • providerにconsumerとSTEP02で得た認証キーを適用する
    • 後は公式通りに利用

公式には

consumer.setTokenWithSecret(ACCESS_TOKEN, TOKEN_SECRET);

とだけあり、ACCESS_TOKENやTOKEN_SECRETは、callbackで得られるkeyとsecのペアのことかと思っていた。
しかし、これはSTEP01でcosumerが持っているやつを使わなければいけない。


STEP01

OAuthConsumer consumer = new DefaultOAuthConsumer("XXX","XXX");
OAuthProvider provider = new DefaultOAuthProvider("XXX","XXX");
authUrl = provider.retrieveRequestToken(consumer, CALLBACK_URL);
// accessTokenをsessionやDBに保持 ↓こいつら
System.out.println(consumer.getToken());
System.out.println(consumer.getTokenSecret());
//...

STEP02

//認証元からGETで受け取った認証キーをsessionやDBに保持
//...

STEP03

OAuthProvider provider = (OAuthProvider)session.getAttribute("provider");
OAuthConsumer consumer = new DefaultOAuthConsumer("XXX","XXX");
consumer.setTokenWithSecret("STEP01のaccessTokenKey", "STEP01のaccessTokenSec");
provider.retrieveAccessToken(consumer, "STEP02で認証元からうけとった認証キー");
//あとは普通通り
URL url = new URL("認証が必要なリソースURL");
//...略


~~~
さらにハマった。。

上の手順だとSTEP03を2回以上くりかえすと、2回目からは401がでてしまう。
理由は、retrieveAccessTokenするとaccessTokenとaccessTokenSecretが更新されるから。
なので、

STEP02でretrieveAccessTokenを済ませて置き、そこで新しく発行されるtokenを保持し、STEP03で何度も同じものを使うというふうにしなければいけない。

STEP01

OAuthConsumer consumer = new DefaultOAuthConsumer("XXX","XXX");
OAuthProvider provider = new DefaultOAuthProvider("XXX","XXX");
authUrl = provider.retrieveRequestToken(consumer, CALLBACK_URL);
// accessTokenをsessionやDBに保持 ↓こいつら
System.out.println(consumer.getToken());
System.out.println(consumer.getTokenSecret());
//...

// providerもsessionなんかで保持しておく
session.setAttribute("provider", provider);

STEP02 (retrieveAccessTokenを済ませて置き、そこで新しく発行されるtokenを保持)

OAuthProvider provider = (OAuthProvider)session.getAttribute("provider");
OAuthConsumer consumer = new DefaultOAuthConsumer("XXX","XXX");
provider.retrieveAccessToken(consumer, "GETパラメータでうけとった認証キー");
// ここで実はconsumerのaccesstokenが更新されている。
// のでそいつらを保持しておく
System.out.println(consumer.getToken());
System.out.println(consumer.getTokenSecret());
//...

// providerはもう用済みなので消してよい

STEP03

OAuthConsumer consumer = new DefaultOAuthConsumer("XXX","XXX");
consumer.setTokenWithSecret("STEP02のaccessTokenKey", "STEP02のaccessTokenSec");

//あとは普通通り
URL url = new URL("認証が必要なリソースURL");
//...略

munin-node | mysqlのレプリケーション関係で動かない

mysqlのリプリケーションをやったサーバでmunin-nodeを起動しても動作しなかった
それ以外の状況が全く同じサーバについては普通通りに動いている。

ログをみると、/var/log/munin-node/munin-node.logだけがでている。

sudo -u munin /usr/bin/munin-cron

これで無理やり実行すると、/var/log/munin/munin-update.logに大量の"mysql_"なんたら というエラーが見つかった。

mv /etc/munin/plugins/mysql_* /etc/munin/plugins/bak/

と退避させて2回強制実行するとすべてのログが正常化した。
それでもなお自動実行はされない。
crontabに登録したが、なぜか動かなかった。

/5 * * * * sudo -u munin /usr/bin/munin-cron

ので、仕方なく、スクリプトで走らせることにした。はぁ・・ださい

while(1){
        print "go\n";
        `sudo -u munin /usr/bin/munin-cron`;
        sleep 300;
}

スカッとインストールできないもんかねー

1つのサーバにmysql複数プロセス立ち上げる

基本
MySQLプロセスを一台のサーバで複数起動 [GameCreator'sNote]

mysql dirの初期化だけはこちらの手順
MySQLのデータベースを初期化する - Qiita


つまり

vim /etc/my2.cnf
mkdir /var/lib/mysql2
chown mysql:mysql /var/lib/mysql2

# init dir
su mysql
mysql_install_db --datadir=/var/lib/mysql2
exit

# 
mkdir -pv /var/lib/mysql2
chown mysql:mysql /var/lib/mysql2

# check log. no error
tail -f /var/log/mysqld2.log
# 最終行がこんな感じであればOK
# Version: '5.5.42'  socket: '/var/lib/mysql2/mysql2.sock'  port: 3307  MySQL Community Server (GPL)

# login
mysql -uroot -p --socket=/var/lib/mysql2/mysql2.sock


/etc/my2.cnf

[mysqld]
datadir=/var/lib/mysql2
socket=/var/lib/mysql2/mysql2.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

#log-bin
server-id=1001
port=3307

[mysqld_safe]
log-error=/var/log/mysqld2.log
pid-file=/var/run/mysqld2/mysqld2.pid

perlDBIから2つめのmysqlに接続

my $dbh = DBI->connect("DBI:mysql:database=$DB_NAME;host=localhost;port=3307;mysql_socket=/var/lib/mysql2/mysql2.sock", $user, $pass);

mysql_socketを指定しないと、仮にポート番号などその他の情報がが2つめのmysqlを正しく指していたとしても、何のエラーメッセージもなくデフォルトの1つめのmysqlに接続されてしまう。
最初は1つ目のmysqlに接続されているということに気づかずに少し嵌った。

さくらVPSでmysqlレプリケーションを構築してみる

前提

centos6
mysql5.5

まず、mysql5.5を入れる。

【シンプル】CentOS6にMySQL5.5をyumで簡単にインストールする手順 | 田舎に住みたいエンジニアの日記


最初5.6を入れてすすめていたが、5.1から5.6への移行は推奨されないというのを見て、嫌な予感がして5.5にすることにした。
MySQL 5.1→5.6のmy.cnfの差分とか - (ひ)メモ

service mysqld start で起動するとエラー

これの2と3で解決
[Web] さくらVPSでのメンテナンスについて: ものづくりログ

いくつかのサーバはなぜかさらに別のエラーがでて起動できなかった(復旧にコケたみたいなエラーだった)。エラーログでググってもあまりHITしなかったので、MySQLを初期化する方法を試してみたらすんなりいった。
MySQLのデータベースを初期化する - Qiita

    • 休憩 --

メイン

新規のサーバでセットアップ の節
現場指向のレプリケーション詳説

図9のところはmysqlのバージョンのせいか、できなかった

[mysqld]
server-id=11
master-host=mymaster
master-user=repl
master-password=qa55wd

ので、そこだけ、こちらの手順でやる。
MYSQLレプリケーション設定 - エーエイチレフ linuxサーバー技術情報

# slaveのmysqlにログイン

CHANGE MASTER TO
MASTER_HOST='マスターのIPアドレス',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000004',
MASTER_LOG_POS=189;

で、これをmysqlに打ち込んだあとにさらに下を打つと、ようやくレプリケーションが始まる。

mysql> START SLAVE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

MySQL 5.5 Server as Replication Slave « Code-Kolbold Code Talk

最初は権限の問題でうまくいかなかった
とりあえずすべて接続元からを許可するように「%」とするとうまくいった。(TODO:後から調べる!)
図4’

mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'%' IDENTIFIED BY 'qa55wd';

からの、glassfishからconnection poolして利用

まずは、管理画面でconnection poolの作成
GlassFish v3.1.2.2でのMySQL/JDBC設定

java sourceからの利用

        Connection con = null;
        try {
            DataSource source = (DataSource)new InitialContext().lookup("jdbc/mysql1");
            con = source.getConnection();
            // 接続を使用する
            System.out.println("connection is successs.");
            
            
            try {
                Statement stmt = (Statement) con.createStatement();
                ResultSet rs = stmt.executeQuery("select * from aaa limit 2");
                while(rs.next()){
                    Integer no = rs.getInt("id");
                    String eid = rs.getString("name");

                    System.out.println(id+" : " + name);
                }
            } catch (SQLException ex) {
                Logger.getLogger(GenericResource.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (SQLException e) {
            // エラーのログを取る
            Logger.getLogger(GenericResource.class.getName()).log(Level.SEVERE, null, e);
        } catch (NamingException e) {
            // JNDI内にDataSourceが見つからない
            System.out.println("JNDI内にDataSourceが見つからない");
        } finally {
            if (con != null) {
                try { con.close(); } catch (SQLException e) {}
            }
        }

jax-rsでNoSuchMethodErrorにハマる

問題

java.lang.NoSuchMethodError: com.sun.research.ws.wadl.Response.getRepresentationOrFault()Ljava/util/List;
at com.sun.jersey.server.wadl.WadlGeneratorImpl.createResponse(WadlGeneratorImpl.java:198)
at com.sun.jersey.server.wadl.WadlBuilder.generateResponse(WadlBuilder.java:397)

というエラーが発生。restart-domainすると発生しなくなるが、一度でもdeployするとずっと発生する。



jax-rsに関する依存をこの2つに変えたら問題は起きなくなった。

<dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-bundle</artifactId>
            <version>1.18.1</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.7.7</version>
        </dependency>


参考
spring - REST Exception: java.lang.reflect.InvocationTargetException - Stack Overflow

web server (apache) → app server (glassfish) 構成

web server (apache) → app server (glassfish) の構成にする。
ApacheとGlassFishを連携する mod_proxy編 - Webサービスで起業を目指すプログラマーblog

これによって、無駄にport開放をしなくてよくなった。ユーザのアクセスはすべてapacheの80に集約される。