/**
* @version $Id: CleansingMorphemeHandler.java 1840 2014-04-16 05:38:34Z yukihiro-kinjyo $
*
* 2011/08/09 16:02:33
* @author takayuki-matsumoto
*
* Copyright 2011-2014 TIDAコンソーシアム All Rights Reserved.
*/
package com.tida_okinawa.corona.ui.handlers;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import com.tida_okinawa.corona.CoronaActivator;
import com.tida_okinawa.corona.common.CleansingNameVariable;
import com.tida_okinawa.corona.common.ILogger;
import com.tida_okinawa.corona.correction.common.ExternalProgramExitException;
import com.tida_okinawa.corona.correction.common.FileUtil;
import com.tida_okinawa.corona.correction.morphem.compile.DicCompileExecution;
import com.tida_okinawa.corona.correction.morphem.compile.JumanDicTransfer;
import com.tida_okinawa.corona.correction.morphem.preference.MorphemePreference;
import com.tida_okinawa.corona.internal.ui.util.IFileUtil;
import com.tida_okinawa.corona.internal.ui.util.Kernel;
import com.tida_okinawa.corona.internal.ui.views.model.IUIElement;
import com.tida_okinawa.corona.internal.ui.views.model.IUIProduct;
import com.tida_okinawa.corona.internal.ui.views.model.IUIWork;
import com.tida_okinawa.corona.internal.ui.views.model.impl.CoronaModel;
import com.tida_okinawa.corona.io.IoActivator;
import com.tida_okinawa.corona.io.model.ClaimWorkDataType;
import com.tida_okinawa.corona.io.model.IClaimData;
import com.tida_okinawa.corona.io.model.IClaimWorkData;
import com.tida_okinawa.corona.io.model.ICoronaDicPri;
import com.tida_okinawa.corona.io.model.ICoronaProduct;
import com.tida_okinawa.corona.io.model.ICoronaProject;
import com.tida_okinawa.corona.io.model.dic.ICoronaDic;
import com.tida_okinawa.corona.io.model.table.IFieldHeader;
import com.tida_okinawa.corona.ui.ViewUtil;
import com.tida_okinawa.corona.ui.controllers.MorphemeController;
import com.tida_okinawa.corona.ui.controllers.MorphemeControllerForUI;
import com.tida_okinawa.corona.ui.wizards.CleansingWizard;
/**
* @author takayuki-matsumoto, imai
*/
public class CleansingMorphemeHandler extends AbstractCleansingHandler {
boolean compileSucceed = false;
List<ICoronaDic> checkedDics;
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
super.execute(event);
Shell shell = HandlerUtil.getActiveShell(event);
Kernel.startSuppressSleep();
try {
List<CleansingWizard> wizards = new ArrayList<CleansingWizard>();
for (IUIProduct uiProduct : getProducts()) {
/* 辞書優先度情報は、出力先処理結果から取ってくる */
CleansingWizard wizard = new CleansingWizard(dstWorkList, EXEC_TYPE, uiProduct);
WizardDialog d = new WizardDialog(shell, wizard);
if (d.open() != Dialog.OK) {
return false;
}
wizards.add(wizard);
}
int i = 0;
for (IUIProduct uiProduct : getProducts()) {
CleansingWizard wizard = wizards.get(i++);
ICoronaProduct product = uiProduct.getObject();
List<IClaimData> claims = product.getClaimDatas();
for (IClaimData claim : claims) {
int claimId = claim.getId();
Collection<Integer> fieldIds = product.getMiningFields(claimId);
for (Integer fieldId : fieldIds) {
IClaimWorkData srcWork = null;
for (IClaimWorkData work : srcWorkList) {
if ((work.getClaimId() == claimId) && (work.getFieldId() == fieldId)) {
srcWork = work;
break;
}
}
if (!(srcWork != null && product.getId() == srcWork.getProductId())) {
continue;
}
/* クレンジング対象のワークデータがあった場合 */
IClaimWorkData dstWork = null;
if (wizard.isFieldSelect()) {
/* フィールド毎の指定あり */
for (IClaimWorkData work : dstWorkList) {
if ((work.getClaimId() == claimId) && (work.getFieldId() == fieldId)) {
dstWork = work;
break;
}
}
if (dstWork == null) {
/* 対応する辞書リストが取得できない場合、後続の処理を行わない */
continue;
}
// 辞書を取得
checkedDics = getDictionary(wizard.getFieldDicPriorityList(dstWork));
} else {
/* 共通の場合 */
checkedDics = getDictionary(wizard.getDicPriorityList());
}
try {
step1(uiProduct); // 辞書コンパイル
if (compileSucceed) {
step2Fields(uiProduct, srcWork); // 形態素・係り受け解析実行
}
} catch (InterruptedException e1) {
IClaimWorkData cwd = product.getClaimWorkData(claimId, EXEC_TYPE, fieldId);
if (cwd != null) {
/*
* 失敗したので処理日時が入っていない。日時を入れるためにupdate。
* Memo ただし、処理前に前回結果を破棄していないので、前回の結果と混ざる恐れあり。
*/
cwd.update();
}
}
if (dstWork != null && dstWork.getWorkdataId() == 0 && dstWork.getLasted() != null) {
// 処理結果後のクレームワークデータでマップを置き換える
// Memo dstWorkを作成した時、ターゲットに追加してしまえば置き換えずに済むのでは?
IClaimWorkData cwd = product.getClaimWorkData(claimId, EXEC_TYPE, fieldId);
wizard.updateDicPriMap(dstWork, cwd);
}
}
}
/*
* 保存処理
* IClaimWorkDataがDBに保存されてからでないと、workId==0により、優先度を保存できないことがあるため、
* 処理が終わってから保存
*/
wizard.saveDicPriList();
// TODO dstWorkListじゃなくて、実際に処理したIClaimWorkDataの一覧から取得する
if (dstWorkList.size() > 0) {
IClaimWorkData targetWork = dstWorkList.get(dstWorkList.size() - 1);
IClaimWorkData claimWorkData = getClaimWorkData(uiProduct, EXEC_TYPE, targetWork.getFieldId(), targetWork.getClaimId());
if (claimWorkData != null && claimWorkData.getLasted() != null) {
/* ダイアログメッセージ用に処理した列名を取得 */
StringBuilder dialogMessage = new StringBuilder();
dialogMessage.append(CleansingNameVariable.MORPH_DEPEND);
dialogMessage.append("が終了しました。\n\n対象列:\n");
for (int ch = 0; ch < (dstWorkList.size()); ch++) {
IClaimData claimData = IoActivator.getService().getClaimData(claimWorkData.getClaimId());
IFieldHeader header = claimData.getFieldInformation(dstWorkList.get(ch).getFieldId());
dialogMessage.append(" [");
dialogMessage.append(header.getName());
dialogMessage.append("]\n");
}
/* 処理結果ダイアログを表示 */
MessageDialog.openInformation(shell, CleansingNameVariable.MORPH_DEPEND + "終了", dialogMessage.toString());
}
}
}
} catch (InvocationTargetException | PartInitException e) {
e.printStackTrace(System.err);
throw new ExecutionException("形態素解析に失敗しました。", e);
} finally {
Kernel.stopSuppressSleep();
}
ViewUtil.refreshProjectExplorer(0);
return null;
}
private static final ClaimWorkDataType EXEC_TYPE = ClaimWorkDataType.DEPENDENCY_STRUCTURE;
@Override
ClaimWorkDataType getExecType() {
return EXEC_TYPE;
}
private static List<ICoronaDic> getDictionary(List<ICoronaDicPri> priList) {
List<ICoronaDic> list = new ArrayList<ICoronaDic>();
for (ICoronaDicPri pri : priList) {
/* 辞書を設定 */
if (!pri.isInActive()) {
list.add(IoActivator.getService().getDictionary(pri.getDicId()));
}
}
return list;
}
// Step1: 辞書コンパイル
private void step1(final IUIProduct uiProduct) throws InvocationTargetException, InterruptedException {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
Shell shell = window.getShell();
ProgressMonitorDialog dialog1 = new ProgressMonitorDialog(shell);
dialog1.run(true, false, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
compileSucceed = compileDic(uiProduct, monitor);
ILogger logger = CoronaActivator.getDefault().getLogger();
/* サーバーモード -> 辞書転送(辞書コンパイル・ターゲット切り替え時)kobayshi */
JumanDicTransfer dt = new JumanDicTransfer();
try {
dt.dicTrancefer(logger);
} catch (IOException e1) {
e1.printStackTrace(logger.getErrStream());
}
}
});
}
private static void step2Fields(IUIProduct uiProduct, IClaimWorkData cwd) throws InvocationTargetException, InterruptedException, PartInitException {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IUIWork uiWork = CoronaModel.INSTANCE.getWork(uiProduct, cwd);
MorphemeController controller = new MorphemeControllerForUI(uiProduct, uiWork, null);
// TODO NewProgressに入れる意味ないよね。一つ入れては一回実行してるし。
NewProgress newProgress = new NewProgress();
newProgress.addRunnable(controller);
Shell shell = window.getShell();
ProgressMonitorDialog dialog2 = new ProgressMonitorDialog(shell);
long s = System.currentTimeMillis();
// 解析実行
dialog2.run(true, true, newProgress);
CoronaActivator.debugLog("形態素解析時間:" + (System.currentTimeMillis() - s) + "mSec");
}
// Step1: 辞書のエクスポート, コンパイル
private boolean compileDic(IUIProduct uiProduct, IProgressMonitor monitor) {
Assert.isLegal(uiProduct.getObject() != null);
monitor.beginTask("辞書更新エクスポート", 2);
ICoronaProduct product = uiProduct.getObject();
ICoronaProject project = IoActivator.getService().getProject(product.getProjectId());
/* juman 辞書の作成先 */
File dicDir = MorphemePreference.getJumanDicDir();
/* 辞書のリスト */
File[] dicFiles = getDicFiles(dicDir);
/* プロジェクトの辞書エクスポート */
String encoding = MorphemePreference.convSJIS() ? "MS932" : "UTF-8";
project.exportDictionarys(dicDir.getAbsolutePath(), encoding);
monitor.worked(1);
/* ターゲットの辞書エクスポート */
product.exportDictionarys(dicDir.getAbsolutePath(), encoding);
monitor.worked(1);
/* product_folder: 辞書ファイルのワークスペース内の退避先 */
IFolder product_folder = getProductFolder(uiProduct);
boolean force = !product_folder.getFile("jumandic.pat").exists();
// note: ワークスペースに退避したjumandic.patがなければ、dic の更新がなくても作成する
/* 辞書更新 */
ILogger logger = CoronaActivator.getDefault().getLogger();
DicCompileExecution ce = new DicCompileExecution(logger, monitor);
try {
boolean isUpdated = ce.compile(dicFiles, force);
/* Jumanが参照する辞書ファイル */
File[] juman_dic_files = ce.getJumanDicFiles();
if (isUpdated) {
// 辞書を更新した -> juman/dic と ワークスペースに退避
IFileUtil.copy(product_folder, juman_dic_files);
} else {
// 辞書の更新なし -> ワークスペースに退避してあるものを juman/dicに写す
assert (!force);
for (int i = 0; i < juman_dic_files.length; i++) {
File to = juman_dic_files[i];
IFile from = product_folder.getFile(to.getName());
// ハッシュをチェックして同じファイルならコピー不要
byte[] toMD5 = new byte[0];
if (to.exists()) {
toMD5 = FileUtil.calcMD5(to);
}
byte[] fromMD5 = FileUtil.calcMD5(from.getContents());
if (!Arrays.equals(fromMD5, toMD5)) {
InputStream is = from.getContents();
try {
FileUtil.copy(to, is);
} finally {
is.close();
}
}
}
}
return true;
} catch (ExternalProgramExitException e) {
logger.getErrStream().println("辞書の作成に失敗しました:" + e);
e.printStackTrace();
} catch (FileNotFoundException e) {
logger.getErrStream().println("ファイルが見つかりません:" + e);
e.printStackTrace();
} catch (InterruptedException | IOException | CoreException e) {
e.printStackTrace();
}
return false;
}
File[] getDicFiles(File dicDir) {
File[] dicFiles = new File[checkedDics.size()];
for (int i = 0; i < checkedDics.size(); i++) {
ICoronaDic dic = checkedDics.get(i);
File ddic = new File(dicDir, dic.getName());
dicFiles[i] = FileUtil.transPathExtension(ddic, "dic");
}
return dicFiles;
}
/**
* ワークスペース内の「ターゲット」フォルダーを取得
*
* @param product
* @return
*/
IFolder getProductFolder(IUIProduct uiProduct) {
IFolder folder = uiProduct.getResource();
try {
folder.refreshLocal(IResource.DEPTH_ONE, null);
} catch (CoreException e) {
//
}
return folder;
}
/**
* {@link IFile} to {@link File}
*
* @param file
* @return
*/
File toFile(IFile file) {
IPath path = file.getLocation();
String ospath = path.toOSString();
return new File(ospath);
}
@Override
public boolean isEnabled() {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window == null) {
return false;
}
/* WorkData以外 */
IStructuredSelection ss = (IStructuredSelection) window.getActivePage().getSelection();
IUIElement target = null;
if (ss != null) {
for (Object element : ss.toArray()) {
/* 複数フィールド選択時は、親オブジェクトが共通以外、またはWorkDataTypeが異なる場合は拒否 */
if (target != null) {
if (element instanceof IUIElement) {
if (((IUIElement) element).getParent() != target.getParent()) {
return false;
} else if (element instanceof IUIWork) {
return super.isEnabled();
}
}
} else {
if (element instanceof IUIElement) {
target = (IUIElement) element;
} else {
return false;
}
}
}
}
return super.isEnabled();
}
@Override
protected boolean isEnabled(ClaimWorkDataType type) {
switch (type) {
case CORRECTION_MISTAKES:
return true;
}
return false;
}
static class NewProgress implements IRunnableWithProgress {
List<IRunnableWithProgress> runs = new ArrayList<IRunnableWithProgress>();
public void addRunnable(IRunnableWithProgress runnable) {
if (runnable != null) {
runs.add(runnable);
}
}
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
for (IRunnableWithProgress run : runs) {
run.run(monitor);
}
}
}
}