/*******************************************************************************
* Copyright (c) 2013 hangum.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* hangum - initial API and implementation
******************************************************************************/
package com.hangum.tadpole.mongodb.erd.core.dnd;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.Request;
import org.eclipse.gef.dnd.AbstractTransferDropTargetListener;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import com.hangum.tadpole.commons.exception.dialog.ExceptionDetailsErrorDialog;
import com.hangum.tadpole.commons.libs.core.define.PublicTadpoleDefine;
import com.hangum.tadpole.commons.libs.core.message.CommonMessages;
import com.hangum.tadpole.engine.query.dao.mongodb.CollectionFieldDAO;
import com.hangum.tadpole.engine.query.dao.system.UserDBDAO;
import com.hangum.tadpole.mongodb.core.query.MongoDBQuery;
import com.hangum.tadpole.mongodb.erd.core.Messages;
import com.hangum.tadpole.mongodb.erd.core.editor.TadpoleMongoDBERDEditor;
import com.hangum.tadpole.mongodb.erd.core.relation.RelationUtil;
import com.hangum.tadpole.mongodb.erd.core.utils.TadpoleModelUtils;
import com.hangum.tadpole.mongodb.erd.stanalone.Activator;
import com.hangum.tadpole.mongodb.model.Column;
import com.hangum.tadpole.mongodb.model.DB;
import com.hangum.tadpole.mongodb.model.MongodbFactory;
import com.hangum.tadpole.mongodb.model.Table;
/**
* Explorer의 테이블 명을 넘겨 받아서 erd에 테이블을 그려줍니다.
*
* @author hangum
*
*/
public class TableTransferDropTargetListener extends AbstractTransferDropTargetListener {
private static final Logger logger = Logger.getLogger(TableTransferDropTargetListener.class);
private MongodbFactory tadpoleFactory = MongodbFactory.eINSTANCE;
/** object view에서 넘어오는 테이블 네임 인텍스, 0번은 스키마 이름(rdb에서만 사용하는.) */
private int IDX_TABLE_NAME = 1;
private TadpoleMongoDBERDEditor mongoEditor = null;
private TableTransferFactory transferFactory = new TableTransferFactory();
private UserDBDAO userDB;
private DB db;
public TableTransferDropTargetListener(EditPartViewer viewer, Transfer xfer) {
super(viewer, xfer);
}
public TableTransferDropTargetListener(TadpoleMongoDBERDEditor mongoEditor, EditPartViewer viewer, UserDBDAO userDB, DB db) {
super(viewer, TextTransfer.getInstance());
this.mongoEditor = mongoEditor;
this.userDB = userDB;
this.db = db;
}
@Override
protected Request createTargetRequest() {
CreateRequest request = new CreateRequest();
request.setFactory(transferFactory);
return request;
}
@Override
protected void updateTargetRequest() {
((CreateRequest)getTargetRequest()).setLocation(getDropLocation());
}
@Override
protected void handleDragOver() {
getCurrentEvent().detail = DND.DROP_COPY;
super.handleDragOver();
}
@Override
protected void handleDrop() {
String strDragSource = (String)getCurrentEvent().data;
try {
String[] arrayDragSourceData = StringUtils.splitByWholeSeparator(strDragSource, PublicTadpoleDefine.DELIMITER);
int sourceDBSeq = Integer.parseInt(arrayDragSourceData[0]);
if(userDB.getSeq() != sourceDBSeq) {
MessageDialog.openWarning(null, CommonMessages.get().Warning, Messages.get().TableTransferDropTargetListener_1); //$NON-NLS-1$
return;
}
} catch(Exception e) {
logger.error("dragger error", e); //$NON-NLS-1$
MessageDialog.openError(null,CommonMessages.get().Error, "Draging exception : " + e.getMessage()); //$NON-NLS-1$
return;
}
final int nextTableX = getDropLocation().x;
final int nextTableY = getDropLocation().y;
final String strFullData = StringUtils.substringAfter(strDragSource, PublicTadpoleDefine.DELIMITER);
final String [] arryTables = StringUtils.splitByWholeSeparator(strFullData, PublicTadpoleDefine.DELIMITER_DBL);
final Map<String, List<CollectionFieldDAO>> mapTable = new HashMap<>();
Job job = new Job("Painting model") {
@Override
public IStatus run(IProgressMonitor monitor) {
monitor.beginTask("Painting table object", IProgressMonitor.UNKNOWN);
try {
for (int i=0; i<arryTables.length; i++) {
String strTable = arryTables[i];
monitor.subTask(String.format("Working %s/%s", i, arryTables.length));
String[] arryTable = StringUtils.splitByWholeSeparator(strTable, PublicTadpoleDefine.DELIMITER);
if(arryTable.length == 0) continue;
String tableName = arryTable[IDX_TABLE_NAME];
mapTable.put(tableName, getColumns(tableName));
}
} catch(Exception e) {
logger.error("ERD Initialize excepiton", e);
return new Status(Status.WARNING, Activator.PLUGIN_ID, e.getMessage());
} finally {
monitor.done();
}
/////////////////////////////////////////////////////////////////////////////////////////
return Status.OK_STATUS;
}
};
// job의 event를 처리해 줍니다.
job.addJobChangeListener(new JobChangeAdapter() {
public void done(IJobChangeEvent event) {
final IJobChangeEvent jobEvent = event;
Display display = mongoEditor.getEditorSite().getShell().getDisplay();
display.syncExec(new Runnable() {
public void run() {
if(jobEvent.getResult().isOK()) {
paintingModel(nextTableX, nextTableY, arryTables, mapTable);
} else {
MessageDialog.openError(null, CommonMessages.get().Confirm, jobEvent.getResult().getMessage());
}
}
}); // end display.asyncExec
} // end done
}); // end job
job.setName(userDB.getDisplay_name());
job.setUser(true);
job.schedule();
// super.handleDrop();
}
/**
* painting model
*
* @param nextTableX
* @param nextTableY
* @param arryTables
* @param mapTable
*/
private void paintingModel(int nextTableX, int nextTableY, String [] arryTables, Map<String, List<CollectionFieldDAO>> mapTable) {
Rectangle prevRectangle = null;
int originalX = nextTableX;
int intCount = 1;
for (String strTable : arryTables) {
String[] arryTable = StringUtils.splitByWholeSeparator(strTable, PublicTadpoleDefine.DELIMITER);
if(arryTable.length == 0) continue;
String tableName = arryTable[IDX_TABLE_NAME];
String refTableNames = "'" + tableName + "',"; //$NON-NLS-1$ //$NON-NLS-2$
// 이미 editor 상에 테이블 정보를 가져온다.
Map<String, Table> mapDBTables = new HashMap<String, Table>();
for (Table table : db.getTables()) {
mapDBTables.put(table.getName(), table);
refTableNames += "'" + table.getName() + "',"; //$NON-NLS-1$ //$NON-NLS-2$
}
refTableNames = StringUtils.chompLast(refTableNames, ","); //$NON-NLS-1$
// 이미 등록되어 있는 것이 아니라면
if(mapDBTables.get(tableName) == null) {
// 테이블 모델 생성
Table tableModel = tadpoleFactory.createTable();
tableModel.setName(tableName);
tableModel.setDb(db);
if(prevRectangle == null) {
prevRectangle = new Rectangle(nextTableX,
nextTableY,
TadpoleModelUtils.END_TABLE_WIDTH,
TadpoleModelUtils.END_TABLE_HIGHT);
} else {
// 테이블의 좌표를 잡아줍니다.
prevRectangle = new Rectangle(nextTableX,
nextTableY,
TadpoleModelUtils.END_TABLE_WIDTH,
TadpoleModelUtils.END_TABLE_HIGHT);
}
tableModel.setConstraints(prevRectangle);
// 다음 좌표를 계산합니다.
nextTableX = originalX + (TadpoleModelUtils.GAP_WIDTH * intCount);
intCount++;
try {
// 컬럼 모델 생성
for (CollectionFieldDAO columnDAO : mapTable.get(tableName)) {
Column column = tadpoleFactory.createColumn();
column.setField(columnDAO.getField());
column.setKey(columnDAO.getKey());
column.setType(columnDAO.getType());
if("BasicDBObject".equals(columnDAO.getType())) {
makeSubDoc(tableModel, column, columnDAO);
}
column.setTable(tableModel);
}
mapDBTables.put(tableName, tableModel);
RelationUtil.calRelation(userDB, mapDBTables, db, refTableNames);//RelationUtil.getReferenceTable(userDB, refTableNames));
} catch(Exception e) {
logger.error("GEF Table Drag and Drop Exception", e); //$NON-NLS-1$
Status errStatus = new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e); //$NON-NLS-1$
ExceptionDetailsErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),CommonMessages.get().Error, Messages.get().TadpoleModelUtils_2, errStatus); //$NON-NLS-1$
}
transferFactory.setTable(tableModel);
} else {
transferFactory.setTable(mapDBTables.get(tableName));
}
}
}
/**
* add sub document
*
* @param tableModel
* @param parentColumn
* @param columnDAO
*/
private void makeSubDoc(Table tableModel, Column parentColumn, CollectionFieldDAO columnDAO) {
for (CollectionFieldDAO cfDAO : columnDAO.getChildren()) {
Column column = tadpoleFactory.createColumn();
column.setField(cfDAO.getField());
column.setKey(cfDAO.getKey());
column.setType(cfDAO.getType());
if("BasicDBObject".equals(cfDAO.getType())) {
makeSubDoc(tableModel, column, cfDAO);
}
//
// column.setTable(tableModel);
// 위의 커럼안에 테이블이 존재하면 서브 컬럼마다 테이블이 중복으로 표시된다.
// 그러나 위의 코드를 삭제하면 The object 'com.hangum.tadpole.mongodb.model.impl.ColumnImpl@b98167 (field: serverStatus, type: Integer, default: null, logicalField: null, key: NO, comment: null)' is not contained in a resource.
// 오류가 발생하고
// 참고합니다 (http://andy.ekiwi.de/?p=1006)
parentColumn.getSubDoc().add(column);
}
}
/**
* table의 컬럼 정보를 가져옵니다.
*
* @param strTBName
* @return
* @throws Exception
*/
public List<CollectionFieldDAO> getColumns(String strTBName) throws Exception {
return MongoDBQuery.collectionColumn(userDB, strTBName);
}
}