/** * @version $Id: MorphemeController.java 1839 2014-04-16 02:33:51Z yukihiro-kinjyo $ * * 2011/08/29 21:30:11 * @author imai * * Copyright 2011-2014 TIDAコンソーシアム All Rights Reserved. */ package com.tida_okinawa.corona.ui.controllers; import static com.tida_okinawa.corona.common.CleansingNameVariable.MORPH_DEPEND; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import com.tida_okinawa.corona.CoronaActivator; import com.tida_okinawa.corona.common.Encoding; import com.tida_okinawa.corona.common.ILogger; import com.tida_okinawa.corona.correction.controller.IListener; import com.tida_okinawa.corona.correction.morphem.Morpheme; import com.tida_okinawa.corona.correction.morphem.MorphemeRelationProcessor; import com.tida_okinawa.corona.correction.morphem.preference.MorphemePreference; import com.tida_okinawa.corona.io.model.ClaimWorkDataType; import com.tida_okinawa.corona.io.model.IClaimWorkData; import com.tida_okinawa.corona.io.model.ICoronaProduct; import com.tida_okinawa.corona.ui.UIActivator; import com.tida_okinawa.corona.ui.data.ErratumCorrectionRecord; import com.tida_okinawa.corona.ui.data.MorphemeRecord; /** * UI->形態素・係り受け解析処理 * * @author imai * */ public class MorphemeController extends ClaimWorkDataController<ErratumCorrectionRecord, MorphemeRecord> { /** * KNPを実行するかどうか */ final boolean doKnp; private String bundleLocation; private boolean convSJIS; /** * ターゲットに紐づいている問合せデータ(誤記補正済み)に対して、形態素・係り受け解析を実行するインスタンスのコンストラクタ。 * * @param product * 形態素・係り受け解析に使用する辞書の最終更新日 * @param doKnp * KNPを実行するかどうか * @param listener * 処理結果を受け取るリスナー (EditorInput) */ public MorphemeController(ICoronaProduct product, boolean doKnp, IListener<MorphemeRecord> listener) { super(MORPH_DEPEND, product, ClaimWorkDataType.CORRECTION_MISTAKES, ClaimWorkDataType.DEPENDENCY_STRUCTURE, listener); this.doKnp = doKnp; } /** * @param product * 解析対象のターゲット * @param workS * 入力データ * @param doKnp * KNPを実行するかどうか * @param listener * 処理結果を受け取るリスナー (EditorInput) */ public MorphemeController(ICoronaProduct product, IClaimWorkData workS, boolean doKnp, IListener<MorphemeRecord> listener) { super(MORPH_DEPEND, product, workS, ClaimWorkDataType.DEPENDENCY_STRUCTURE, listener); this.doKnp = doKnp; } /** * @param product * 解析対象のターゲット * @param inputWorks * 入力データ * @param doKnp * KNPを実行するかどうか * @param listener * 処理結果を受け取るリスナー (EditorInput) */ public MorphemeController(ICoronaProduct product, List<IClaimWorkData> inputWorks, boolean doKnp, IListener<MorphemeRecord> listener) { super(MORPH_DEPEND, product, inputWorks, ClaimWorkDataType.DEPENDENCY_STRUCTURE, listener); this.doKnp = doKnp; } /** * プラグイン以外から呼び出す場合のコンストラクタ。juman, knpの場所を特定するために、bundleLocationが必要 * * @param product * 形態素・係り受け解析に使用する辞書の最終更新日 * @param doKnp * KNPを実行するかどうか * @param bundleLocation * correction.externalプラグインがバンドルされているパス。 * @param convSJIS * @param listener * 処理結果を受け取るリスナー (EditorInput) */ public MorphemeController(ICoronaProduct product, boolean doKnp, String bundleLocation, boolean convSJIS, IListener<MorphemeRecord> listener) { this(product, doKnp, listener); this.bundleLocation = bundleLocation; this.convSJIS = convSJIS; } /** * juman / knp の実行用 * <p> * サーバー利用時は、スレッドごとに引数が違うので、スレッド数分を用意する * </p> */ MorphemeRelationProcessor[] processors; @Override protected Controller createController(String title) { Controller controller; // スタンドアロン: プリファレンスのスレッド数, サーバー利用: プリファレンスのサーバー設定 int nThread = MorphemePreference.getKnpServerNumber(); if (nThread <= 0) { // スタンドアローン // プリファレンスのスレッド数に従う controller = new Controller(title, Runtime.getRuntime().availableProcessors()); } else { controller = new Controller(title, nThread); } // Juman, KNP 実行用 int n = controller.getThreadNum(); // スレッド数(=サーバーのプロセス数の合計) processors = new MorphemeRelationProcessor[n]; if (bundleLocation != null) { for (int threadId = 0; threadId < n; threadId++) { processors[threadId] = new MorphemeRelationProcessor(threadId, bundleLocation); } } else { for (int threadId = 0; threadId < n; threadId++) { processors[threadId] = new MorphemeRelationProcessor(threadId); } } return controller; } @Override ErratumCorrectionRecord createRecordImpl(int claimId, int fieldId, int recordId, String text) { return new ErratumCorrectionRecord(claimId, fieldId, recordId, text); } @Override IListener<MorphemeRecord> createCommitter() { return new ClaimWorkDataRecordCommitter<MorphemeRecord>(product, typeR) { @Override public void end(IProgressMonitor monitor) { StringBuffer note = new StringBuffer(claimWorkData.getNote()); if (note.length() > 0) { note.append(","); //$NON-NLS-1$ } ClaimWorkDataType type = claimWorkData.getClaimWorkDataType(); note.append(type.getName()); note.append(":").append(doKnp); //$NON-NLS-1$ /* DBでの文字数制限 */ if (note.length() > 255) { note.delete(0, note.length() - 255); } claimWorkData.setNote(note.toString()); claimWorkData.commit(monitor); } }; } @Override MorphemeRecord execImpl(ErratumCorrectionRecord record) { try { /* 抽出・補正に、解析処理を要求 */ final Morpheme m = new Morpheme(processors[controller.getThreadId()]); String text = record.getResult(); if (text == null) { System.err.println(Messages.MorphemeController_errNullRecord + record.getRecordId()); text = ""; //$NON-NLS-1$ } ByteArrayOutputStream err = new ByteArrayOutputStream(); List<String> morphemeResult; if (bundleLocation != null) { morphemeResult = m.process(text, doKnp, err, convSJIS, Messages.MorphemeController_PERIOD, Messages.MorphemeController_QUESTION); /* 句点で区切って処理する */ } else { morphemeResult = m.process(text, doKnp, err, Messages.MorphemeController_PERIOD, Messages.MorphemeController_QUESTION); /* 句点で区切って処理する */ } err(record, err); MorphemeRecord resultRecord = new MorphemeRecord(record.getClaimId(), record.getFieldId(), record.getRecordId(), text, morphemeResult); return resultRecord; } catch (RuntimeException e) { e.printStackTrace(); if (CoronaActivator.getDefault() != null) { CoronaActivator.getDefault().getLogger().getErrStream().println(e.getLocalizedMessage()); } // return dummy result return new MorphemeRecord(record.getClaimId(), record.getFieldId(), record.getRecordId(), record.getResult(), new ArrayList<String>(0)); } } /** * KNPのエラー原文を日本語にして返す. * エラー扱いしないものは、nullを返す. * * @param errmsg * エラー原文 * @return 日本語訳したエラー文 */ private static String getDetailErrorMessage(String errmsg) { /* その他の理由がわかったら随時追加する */ if (errmsg.contains("Too many mrph")) { //$NON-NLS-1$ return (Messages.MorphemeController_tooManyMrph); } else if (errmsg.contains("bunsetsu")) { //$NON-NLS-1$ return (Messages.MorphemeController_tooManyBunsetsu); } else if (errmsg.contains("older than rule file")) { //$NON-NLS-1$ /* 解析はできているので */ return null; } else if (errmsg.contains("init_case_frame")) { //$NON-NLS-1$ /* Memo 詳しい理由を出したい */ } else if (errmsg.contains("new_cky_data")) { //$NON-NLS-1$ /* Memo 詳しい理由を出したい */ } else if (errmsg.contains("pathopen") | errmsg.contains("tie")) { //$NON-NLS-1$ //$NON-NLS-2$ /* KNP4にした途端色々出始めたのでスルーする #1145 */ return null; } return ""; //$NON-NLS-1$ } /** * コンソールとLogViewにエラー出力する * * @param record * @param err */ private static void err(ErratumCorrectionRecord record, ByteArrayOutputStream err) { if (CoronaActivator.getDefault() == null) { return; } ILogger logger = CoronaActivator.getDefault().getLogger(); synchronized (logger) { if (err.size() == 0) { return; } /* * 解析に失敗した原文...(###文字) * _ 解析失敗。[詳細なメッセージ(メッセージ原文)], ... * _ Claim:### Field:### Rec:### */ /* 解析に失敗した原文 */ StringBuffer textBuf = new StringBuffer(64).append(Messages.MorphemeController_body); String text = record.getResult(); if (text.length() < 25) { textBuf.append(text); } else { textBuf.append(text.substring(0, 25)).append(Messages.MorphemeController_ellipsis).append(text.length()) .append(Messages.MorphemeController_stringCount); } StringBuffer errBuf = new StringBuffer(256); // 詳細なメッセージ(メッセージ原文) try { // ShiftJIS -> UTF-8 にして出力 InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(err.toByteArray()), Encoding.MS932.toString()); BufferedReader reader = new BufferedReader(isr); /* エラーメッセージ作成 */ String errmsg; while ((errmsg = reader.readLine()) != null) { String detail = getDetailErrorMessage(errmsg); if (detail != null) { errBuf.append("[").append(detail).append("(").append(errmsg).append(")] "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } } catch (IOException e) { e.printStackTrace(); } if (errBuf.length() == 0) { return; } errBuf.append("\n\tClaim:").append(record.getClaimId()).append(" Field:").append(record.getFieldId()).append(" Rec:").append(record.getRecordId()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ /* コンソールにエラーメッセージを出力 */ logger.getOutStream().println(textBuf.toString()); logger.getErrStream().println(errBuf.toString()); /* 解析失敗の情報をLogViewに書きだす */ errBuf.insert(0, textBuf.toString()); CoronaActivator.log(new Status(IStatus.ERROR, UIActivator.PLUGIN_ID, errBuf.toString()), false); /* エラーログビューを表示する */ Display.getDefault().asyncExec(new Runnable() { @Override public void run() { try { PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView("org.eclipse.pde.runtime.LogView"); //$NON-NLS-1$ } catch (PartInitException e) { } } }); } } }