2014年7月2日水曜日

MySQLで動的DDL

見るよりやってみる。が分かりやすいかもしれません。

キーワード
PREPAREステートメント , executeステートメント

Procedureの実装

drop procedure if exists cust_createtable;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `cust_createtable` (IN table_nane varchar(100))
  READS SQL DATA
BEGIN
  declare col varchar(4000);
  set col = 'col1 varchar(100)';
  select CONCAT('create table ',table_nane,' (' , col , ')') into @qry;
  PREPARE ddl_stmt from @qry;
  execute ddl_stmt;
end
;
;;
DELIMITER ;

呼び出し

call cust_createtable('test3')

確認


show tables like 'test%'

javaでzipファイルを作成する

javaでzipな要件が出てきたのでちょっと書いてみました。

javaに関してはド素人なので文法やお約束などすっとばしてる可能性大ですがご容赦ください。


【やること】

・zipファイル名、対象のファイル、格納する際のパス加工を指定してzip処理を行う。
・元のファイルは特にいじらない。
・ディレクトリ指定された場合、ディレクトリ内のすべてのファイルを対象とする。


【実施環境】

CentOS6.5
java version "1.6.0_30"
OpenJDK Runtime Environment (IcedTea6 1.13.3) (rhel-5.1.13.3.el6_5-x86_64)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)


【注意点】

いろんな情報を見ていると、JRE1.6系では全角のファイル名が扱えないとか
何とか、いろんな情報が出ているようです。
その為の検証だったのですが、結果、問題ありませんでした。
⇒その後の検証で原因発覚。利用している解凍ツールが対応していただけでした。


ant.jarが持つ、Zip圧縮ツールを使うサンプルです。

【ソースの中身でちょっと分かりづらい仕様の説明】

・存在しないファイルを指定した場合、ゴミZipだけが残る事象が確認されたため
 回避するためにNotFoundExceptionを発生させています。
・絶対パス指定の場合、私の環境ではきれいにフォルダ構成まで作られてしまったため
 それを回避するためにZipEntryへは相対パス以下のフォルダ指定をするようにしました。
・ライブラリを、java.io.zipへ戻せるように、Encodingは外から指定可能とし、
 指定された場合のみ使うようにしました。



【ソース】


汎用性を持たせるため、2つに分けました。

----------------------------------------------------------------
ZipTest.java
----------------------------------------------------------------

import java.io.*;
import java.lang.*;
import java.util.*;
import java.util.ArrayList;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

public class ZipTest{
  public static void main(String[] args){
    File  file;                 //作成するzipファイルの名前
    List<File> files = new ArrayList<File>();
    String baseDirectory = "";
    if (args != null && args.length > 2)
    {
      //引数1 zipファイル名
      file = new File(args[0]);
       
      //引数2 基準ディレクトリ
      baseDirectory = args[1];

      //引数3以降 対象ファイルのパス
      for (int i= 2;i<args.length;i++)
      {
        files.add(new File(args[i]));
      }
      System.out.println(files.size());
    }
    else
    {
      //demo
      file = new File("sample.zip");
      baseDirectory = "/tmp/sample/csv/";
      //圧縮対象を相対パスで指定
      files.add(new File("/tmp/sample/csv/あ.txt"));
      files.add(new File("/tmp/sample/csv/い.txt"));
      files.add(new File("/tmp/sample/csv/ああ.txt"));
      files.add(new File("/tmp/sample/csv/いい.txt"));
    }

    ZipCompressUtils zip;
    zip = new ZipCompressUtils(baseDirectory);

    try{
      zip.Compress(file,files);
    }
    catch (Exception e){
    }
  }
}

----------------------------------------------------------------


実行処理
----------------------------------------------------------------
ZipCompressUtils.java
----------------------------------------------------------------


import java.io.*;
import java.lang.*;
import java.util.*;
//import java.util.zip.ZipEntry;
//import java.util.zip.ZipOutputStream;
import org.apache.tools.zip.*;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

public class ZipCompressUtils
{
  //Private Declare
  static String _rootPath = null;
  static String _encoding = "MS932";
   
  //Constructor
  public ZipCompressUtils()
  {
  }
  public ZipCompressUtils(String rootPath)
  {
    _rootPath = rootPath;
  }
  public ZipCompressUtils(String rootPath , String encoding)
  {
    _rootPath = rootPath;
    _encoding = encoding;
  }
  public boolean Compress(File target , List<File> files) throws Exception {
    try{
      ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(target));
     encode(zos, files);
      if (_encoding != null)
      {
        zos.setEncoding(_encoding);
      }
     zos.close();
      return true;
    }
    catch (Exception e){
      target.delete();
      throw e;
    }
  }
  static void encode(ZipOutputStream zos, List<File> files) throws Exception {
    byte[] buf = new byte[1024];

    //File配列のLoop
    for (File f : files) {
      if (!(f.exists())){
        throw new FileNotFoundException();
      }
      //ディレクトリなら再帰
      if (f.isDirectory()) {
        encode(zos, Arrays.asList(f.listFiles()));
      } else {
        //ファイルの場合の処理
        String zipEntryPath = f.getPath().replace(_rootPath,"").toString().replace("\\", "/");
        ZipEntry entry = new ZipEntry(zipEntryPath);
        zos.putNextEntry(entry);
        InputStream is = new BufferedInputStream(new FileInputStream(f));
        for (;;) 
        {
          int len = is.read(buf);
          if (len < 0) break;
          zos.write(buf, 0, len);
        }
      }
    }
  }
}

2014年6月20日金曜日

SugarCRMの機能「スタジオ」のまとめ

SugarCRMでは、自分たちの使いたいようにカスタマイズできる仕組みが搭載されています。

その中でも、よく使う「スタジオ」について、機能を纏めておこうと思います。

そもそもスタジオって?


 データに関わる部分、入力に関わる部分、表示に関わる部分 のカスタマイズができるツールです。

 「こういう情報があると良いんだけどな~」 とか

 「項目の重要度で入力順を変えたい」 とか

 「一覧にこの項目も出したい」 とか

 そういった事を解決してくれます。



できること


 ○データに関わる部分
  ・データ項目の追加、変更、削除
  ・項目名の変更
  ・データの関連性の追加、変更、削除

  やろうとすれば、自分たちで新しいデータを作り出すこともできます。

 ○入力、表示に関わる部分
  ・編集画面の並び順、位置の変更
  ・詳細画面のレイアウト
  ・一覧に表示する項目、並び順の変更

  データの入出力画面においては、ほぼすべてを対象として出来そうです。

 ○検索
  ・検索条件、表示内容の追加、変更、削除

 ○モジュール名の変更
  ・リード という名前を変えたり。 とかです。 これはちょっと驚きでした。


ということで、メインで出てくる情報のほぼすべてがカスタマイズ可能です。
うまく使って、活用していきたいと思います。

SugarCRMで、コンボボックス(ドロップダウン)の内容をカスタマイズする

1行備忘録です。

行の追加、削除、変更、並び替えなどができます。


1) 該当の定義名を確認

  【管理】 -> 【スタジオ】を選択後、該当のモジュールを選択して、「フィールド」を選択

2) ドロップダウンの編集

  【管理】 -> 【ドロップダウンの編集】 を選択し、ドロップダウンの一覧から上記の定義名を探す
 クリックすると内容が表示されるので、追加、変更、削除 などができます。

アイテム名は英語、表示ラベルは日本語にするのがよさそうです。

2014年6月19日木曜日

SugarCRMのデバッグ (インバウンドメールが取り込まれない)

SugarCRMはphpで動いています。

一応ソフトウェア開発者なので、困った時にはプログラムを解析、
状況によりデバッグ。なんてこともしています。

今回は、SugarCRMのデバッグ。

インバウンドメールをセットアップしても綺麗にケースに入ってこないので
英語のマニュアルを読むよりは、解析、デバッグしてしまおう。という魂胆です。

【前提】

・インバウンドメールは、cron.phpで呼び出す。
・インバウンドメールの処理プログラムは、以下
 /var/www/myapp/sugarcrm/modules/Schedulers/_AddJobsHere.php

【やったこと】

1. ソースを調べる。


 まず、ソースをのぞいてみました。
 cron.phpを動かしたときにNOTICEが出ていた部分を見つけたのですが

 PHP Notice:  Undefined property: InboundEmail::$team_id in  /var/www/myapp/sugarcrm/modules/Schedulers/_AddJobsHere.php on line 104

 これの原因は後回し。おそらく、インバウンドメールに対応するチームを設定していないからと思います。
 ⇒画面で見ても項目見当たらないし、まだそこまでの運用に載ってない。

 で、ログを吐いている部分を確認。

 $GLOBALS['log']->debug('Trying to connect to mailserver for [ '.$a['name'].' ]');

 どこかにログを吐いていそうなことが分かったので、ログのファイルを検索

2.ログの内容を見てみる


 > locate *sugar*.log
 /var/www/myapp/sugarcrm/sugarcrm.log
 /var/www/myapp/sugarcrm/sugarcrm_05_2014.log
 /var/www/myapp/sugarcrm/sugarcrm_06_2014.log

 ということで、月別にログを吐いていそうなことがわかりました。

 ログの中を見ると、fatalだけが出力されています。内容からしてlog4j的なライブラリだろうと思い、ログの設定をしている所を探して、修正することにします。

3.ログ設定の修正

vim /var/www/myapp/sugarcrm/config.php

 前
     'level' => 'fatal',
 
 後
     'level' => 'debug',

 phpなので、何かの再起動は不要のようでした。

4.再度cron.phpを呼び出す


 ものすごい勢いでDEBUG のログが吐かれてました。
 中を見てみて、当りがついたので対処完了。
 config.phpを元に戻して終了です。

ログ関連の概略は掴めたので、この後の運用も楽になりそうです。


ちなみに、発生事象だった「インバウンドメールが入ってこない件」は、
IMAPサーバー側の「未読」「既読」が関係していました。

全てのメールを「未読」に戻したら、大量に入ってきました。

2014年6月16日月曜日

Windows Update後にインターネットにつながらなくなりました。よ。

よくありそうな話です。決して誹謗中傷ではありません。

知り合いのPCがWindowsUpdate後にインターネットにつながらなくなったとの事で
トラブルシュートおよび実機確認、対処を行った内容を纏めておきます。

【事象】

・Windows Update (2014/06)を行った後、インターネットにつながらなくなった。
 ・利用PCは、Windows 8.1

【聞いたこと】

・プロバイダに聞いたところ、ルーターまでのリンクは確立されている。
 ・他のPCではつながる。⇒この時点でPC固有の可能性
 ・某メーカー製、ウィルスソフトがインストール済
 ・Windowsのファイアウォールは設定変更不可。(たぶん某メーカーソフトを検知して自動的にそうなってる)
 ・有線LAN。ケーブルを挿すところのランプはついている。(2つあり点灯、点滅

【ひとまずやったこと】


 ・ipconfig /release
  ⇒rpcサーバを利用できません のエラー
  ⇒これだけだと絞れないので [windows8.1 ネットワークエラー]とかで検索

 ・IPV6が怪しい可能性があるらしく、IPV6を無効化および設定クリア
  ⇒ netsh interface ipv6 reset

 ・某メーカー製、ウィルスソフトを削除

 ・Windowsファイアウォールを無効化 ⇒ウィルスソフトを削除したら案の定設定可能となった

 ・再起動(当然ですが何度もやったそうです)


 電話対応に限界があったので実機を送ってもらう事に。


【実機にて】


 ・とりあえず起動
  ⇒現象は同じ。 ipconfig /release で、RPCエラー


 ・状況調査

  ・固定IPを設定し、ネットワークの接続を試行
   ⇒IPでは接続可能
   ⇒物理的な故障ではないと判断

  ・Windowsエラーログより、根源を調査
    ⇒山盛りなエラーが出てました。

  ・エラーログ内容(ancillary function driver for winsock)を発見
   ⇒エラー発生時期が、WindowsUpdateの時期と一緒。
   ⇒これは、Windowsの標準ドライバ afd.sys というファイルでした。

  ・上記エラー内容を元に調べていったところ、USサイトにて対処法を確認
http://windowsforum.com/threads/dhcp-client-service-fails-to-start.82734/
   ⇒他のキーワードも思いつかないので上から順に見ていきました。
   ⇒SFCという管理ツールで行けるらしいとのこと。


 ・修復の実施
  ・sfc /veriftonly にて、整合性エラーをチェック
  ・sfc /scannow にて、整合性を修復
   ※管理者モードで実行


  処理結果はこんな感じでした
  ------------------------------------------------------

  C:\WINDOWS\system32>sfc /VERIFYONLY
 
  システム スキャンを開始しています。これにはしばらく時間がかかります。
 
  システム スキャンの検証フェーズを開始しています。
  検証 100% が完了しました。
 
  Windows リソース保護により、整合性違反が見つかりました。詳細は
  CBS.Log windir\Logs\CBS\CBS.log に含まれています。例:
  C:\Windows\Logs\CBS\CBS.log。ただし、オフライン サービス シナリオでの
  ログの記録は現在サポートされいません。
 
  C:\WINDOWS\system32>sfc /scannow
 
  システム スキャンを開始しています。これにはしばらく時間がかかります。
 
  システム スキャンの検証フェーズを開始しています。
  検証 100% が完了しました。
 
  Windows リソース保護により、破損したファイルが見つかりましたが、それらの
  一部は修復できませんでした。詳細は CBS.Log windir\Logs\CBS\CBS.log に
  含まれています。例: C:\Windows\Logs\CBS\CBS.log。ただし、オフライン
  サービス シナリオでのログの記録は現在サポートされていません。
 
  システム ファイルの修復の変更は、次回の再起動後に有効になります。
 
  C:\WINDOWS\system32>
  ------------------------------------------------------
  処理ログ出てましたが、Infoしかなく、見づらいのでスルー


 ・OS再起動
  ⇒再起動後、OSが自動でデバイスドライバのインストールを実施


 ・固定IPアドレスを解除
  ⇒DHCPでIP取得され、インターネットへ接続できることを確認


 ・Windows Updateを実施


 ・OS再起動


 ・Windowsが正常に起動し、ネットワーク接続できたことを確認して完了


Windows8.1におけるWindowsUpdate時の障害はいろいろあるようですが、
今回のPCはプリインストールで色々、その他自分で色々。とアプリが山盛りで
純粋にWindows8.1が悪いのでもないんじゃないかな~と思ってます。

ひとまずは解消したので、一安心。といったところです。

2014年6月12日木曜日

Windows 8.1でディスクアクセスが100%となってしまう症状の改善

windows8.1を使用しているのですが、ごくたまに、HDDの使用率が100%となったままとなり、パソコンの動きがものすごく遅くなることがありました。

いい加減いやになってきたので調べてみたら、Microsoftのコミュニティに見解が。

ちなみに、「windows 8.1 system ディスクアクセス」で検索

http://answers.microsoft.com/ja-jp/windows/forum/windows8_1-performance/windows/e51bf236-45e2-4bd5-818d-22819df5cb1e

IPV6が原因かも。ということで、ネットワークの設定を開き、IPV6をOffにしようと思ったら、既にOffでした。

と思ったのも束の間、BluetoothのネットワークプロパティにもIPV6があり、そちらはOn

Offに変更して、しばらく様子見をしていたら、ディスクアクセスが下がり平穏になりました。


コミュニティ上では設定変更による弊害も報告されているようなので一概にはいえませんが、ひとまず安心です。

2014年6月10日火曜日

SugarCRMにて「メール」を自動的に取り込む。

連投です。

先述の勘違い(取引先と見込み客)を気づかせるきっかけとなったのが

「SugarCRMにて「メール」を自動的に取り込みたいのだけどもどうしたらよいか」

という事でした。 (詳しくは前記事を参照ください)



結果としては、「できます」。どうやるかっていうと、

・「メール」の設定で、「インバウンドメール監視のセットアップ」という設定を用いて監視メールアカウントを設定
・cron.php というプログラムがあるので、それを、cronにて実行


というのがざっくりな流れです。

すると、メールのFromが、「取引先」または「取引先担当者」に設定されていれば、
その人の「ケース」として登録されます。


ちなみに、対象がいないと、純粋なケースとして登録されます。


活用はまだまだですが、ひとまず前進です。


SugarCRMの「リード」と「取引先」の概念

今更です。ちゃんと勉強しておけばよかったと思いました。

「リード」 ⇒ 見込客

これがすべての勘違い。というか早とちり

「リード」は、アクションを起こす前。の相手先であって、相手先としてアクションを起こした後は
「取引先」へのコンバートが必要でした。

SugarCRMでは、「取引が発生していない相手先」でも、アクションを管理するのは取引先です。


すべては自分の勘違いです。

類似で、「ケース」 = 「問い合わせ」 ってのも混乱しそう。まだ整理してません。
「コール」 も。
「コール」って「電話応対」と思ってたのですが、受け付けた、電話応対(問合せ)は
コールなのか、ケースなのか。未確認です。


今更なのですがちゃんと勉強してから着手すればよかったと思いました。

2014年6月9日月曜日

RedmineとSVNの連携(SSL自己認証局を利用)

Redmine + SVNの構成はよくあるケースと思いますが、
Redmine + SVN + (SSL) での構成で、Redmine側からの接続にエラーが出ましたので
その時の対応を備忘録として残しておきます。

【構成および概況】

・Redmineと、SVNで2台のサーバ (双方Winサーバ

・ReamineからSVNサーバへの接続はhttp (それ以外も手段もあるのかは知りません

・今まで公開なしの80で運用していたが、公開に合わせて、443での運用へ切り替える

・各々、Internetからの接続は可能な状態(80,443)

【構成イメージ】

 img_20140530_00001

【発生事象】

・SSLを利用すると、其々への直接接続はできるが、RedmineからSVNへの連携設定を行うと、
 エラーとなる。事象としては、「対象がありません」というようなメッセージ

【原因】

・SVNサーバのセキュリティ証明書が、クライアント(Redmineサーバ)で信頼されなかったから

【結果】

・SVNサーバ側で、SSLのセキュリティ証明書を作成し、
 それをRedmine側のクライアント証明書としてインストール

【手順】

・VisualSVNの機能で証明書を作成できるので、ウィザードに従い証明書を作成

・VisualSVNのインストールフォルダに*.pemのファイルが出来ているので
 ,テキストで開き、セキュリティ証明の部分だけを抜き出して別名保存

・上記で保存したセキュリティ証明のファイルを、Redmine側サーバへ持って行って、インストール。
 インストールパスが「個人」だとダメだったので、えいやで「公的な証明機関」へ入れてしまいました。
 ⇒その後、担当がちゃんとしたところへ入れてるはず。

・ReadmineでSSLを利用した接続へ設定変更し、問題なく接続する事を確認。



SSLについては、@ITさんが詳しく解説してくださっています。
http://itpro.nikkeibp.co.jp/article/COLUMN/20071012/284384/?k2