/*******************************************************************************
* Copyright (c) 2015 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.batch.ui.internal.wizard;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.DialogPage;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.dialogs.WizardNewFileCreationPage;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.internal.dialogs.DialogUtil;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.misc.ContainerSelectionGroup;
import org.eclipse.ui.internal.ide.misc.ResourceAndContainerGroup;
import org.eclipse.ui.internal.wizards.newresource.ResourceMessages;
import org.eclipse.ui.wizards.newresource.BasicNewResourceWizard;
import org.jboss.tools.batch.core.BatchConstants;
import org.jboss.tools.batch.core.BatchCorePlugin;
import org.jboss.tools.batch.core.IBatchProject;
import org.jboss.tools.batch.internal.core.impl.BatchProject;
import org.jboss.tools.batch.internal.core.impl.BatchUtil;
import org.jboss.tools.batch.internal.core.impl.definition.BatchJobDefinition;
import org.jboss.tools.batch.ui.JobImages;
import org.jboss.tools.common.EclipseUtil;
import org.jboss.tools.common.ui.widget.editor.IFieldEditor;
import org.jboss.tools.common.ui.widget.editor.SwtFieldEditorFactory;
import org.jboss.tools.common.util.FileUtil;
/**
*
* @author Viacheslav Kabanovich
*
*/
public class NewJobXMLCreationWizard extends BasicNewResourceWizard {
public static final String WIZARD_ID = "org.jboss.tools.batch.ui.internal.wizard.NewJobXMLCreationWizard"; //$NON-NLS-1$
public static final String PAGE_NAME = "newJobFilePage"; //$NON-NLS-1$
private WizardNewBeansXMLFileCreationPage mainPage;
private boolean fOpenEditorOnFinish = true;
/**
* Creates a wizard for creating a new file resource in the workspace.
*/
public NewJobXMLCreationWizard() {
super();
}
public void setVersion(String version) {
if(mainPage.versionEditor != null) {
mainPage.versionEditor.setValue(version.toString());
}
}
public void setID(String id) {
if(mainPage.idEditor != null) {
mainPage.idEditor.setValue(id);
}
}
public String getVersion() {
return mainPage.versionEditor != null ? mainPage.versionEditor.getValueAsString() : mainPage.getInitialJobVersion();
}
@Override
public void addPages() {
super.addPages();
mainPage = new WizardNewBeansXMLFileCreationPage(PAGE_NAME, getSelection());
mainPage.setTitle(WizardMessages.NEW_JOB_XML_WIZARD_TITLE);
mainPage.setDescription(WizardMessages.NEW_JOB_XML_WIZARD_DESCRIPTION);
mainPage.setImageDescriptor(JobImages.getImageDescriptor(JobImages.NEW_JOB_XML_IMAGE));
mainPage.setFileName("job.xml");
addPage(mainPage);
}
@Override
public void init(IWorkbench workbench, IStructuredSelection currentSelection) {
super.init(workbench, currentSelection);
setWindowTitle(WizardMessages.NEW_JOB_XML_WIZARD_TITLE);
setNeedsProgressMonitor(true);
}
@Override
protected void initializeDefaultPageImageDescriptor() {
ImageDescriptor desc = IDEWorkbenchPlugin.getIDEImageDescriptor("wizban/newfile_wiz.png");//$NON-NLS-1$
setDefaultPageImageDescriptor(desc);
}
public boolean isOpenEditorAfterFinish() {
return fOpenEditorOnFinish;
}
public void setOpenEditorAfterFinish(boolean set) {
this.fOpenEditorOnFinish = set;
}
@Override
public boolean performFinish() {
IFile file = mainPage.createNewFile();
if (file == null) {
return false;
}
selectAndReveal(file);
if (fOpenEditorOnFinish) {
// Open editor on new file.
IWorkbenchWindow dw = getWorkbench().getActiveWorkbenchWindow();
try {
if (dw != null) {
IWorkbenchPage page = dw.getActivePage();
if (page != null) {
IDE.openEditor(page, file, true);
}
}
} catch (PartInitException e) {
DialogUtil.openError(dw.getShell(), ResourceMessages.FileResource_errorMessage, e.getMessage(), e);
}
}
return true;
}
class WizardNewBeansXMLFileCreationPage extends WizardNewFileCreationPage {
IFieldEditor versionEditor = null;
IFieldEditor idEditor = null;
public WizardNewBeansXMLFileCreationPage(String pageName, IStructuredSelection selection) {
super(pageName, selection);
}
@Override
public void createControl(Composite parent) {
super.createControl(parent);
validatePage();
}
@Override
protected void initialPopulateContainerNameField() {
super.initialPopulateContainerNameField();
if(!selection.isEmpty() && selection instanceof IStructuredSelection) {
Object o = ((IStructuredSelection)selection).getFirstElement();
IResource r = null;
if(o instanceof IResource) {
r = (IResource)o;
} else if(o instanceof IAdaptable) {
r = (IResource)((IAdaptable)o).getAdapter(IResource.class);
}
if(r != null) {
boolean needMetaInf = false;
boolean needBatchJobs = false;
IPath current = getContainerFullPath();
IProject p = r.getProject();
//Prefer location of existing beans.xml to any other location.
IPath path = getBatchJobsContainer(p);
if(current != null && current.equals(path)) {
return;
}
if(path == null) {
for (IResource f: EclipseUtil.getJavaSourceRoots(p)) {
if(f instanceof IFolder) {
IFolder fm = ((IFolder)f).getFolder(BatchConstants.META_INF);
IFolder bj = fm.getFolder(BatchConstants.BATCH_JOBS);
if(!bj.exists()) {
needBatchJobs = true;
if(fm.exists()) {
bj = fm;
} else {
needMetaInf = true;
bj = ((IFolder)f);
}
}
IPath pth = bj.getFullPath();
if(pth.equals(current) && !needMetaInf) {
return;
}
if(path == null || pth.equals(current)) {
path = pth;
}
}
}
}
if(path != null) {
setContainerFullPath(path);
if(needMetaInf) {
String value = needBatchJobs ? path.append(BatchConstants.META_INF).append(BatchConstants.BATCH_JOBS).toString()
: path.append(BatchConstants.META_INF).toString();
try {
setContainerValue(value);
} catch (NoSuchFieldException e) {
BatchCorePlugin.pluginLog().logError(e);
} catch (IllegalAccessException e) {
BatchCorePlugin.pluginLog().logError(e);
}
}
}
}
}
}
void setContainerValue(String value) throws NoSuchFieldException, IllegalAccessException {
Field f = WizardNewFileCreationPage.class.getDeclaredField("resourceGroup"); //$NON-NLS-1$
f.setAccessible(true);
ResourceAndContainerGroup resourceGroup = (ResourceAndContainerGroup)f.get(this);
Field f2 = ResourceAndContainerGroup.class.getDeclaredField("containerGroup"); //$NON-NLS-1$
f2.setAccessible(true);
ContainerSelectionGroup containerGroup = (ContainerSelectionGroup)f2.get(resourceGroup);
Field f3 = ContainerSelectionGroup.class.getDeclaredField("containerNameField"); //$NON-NLS-1$
f3.setAccessible(true);
Text text = (Text)f3.get(containerGroup);
text.setText(value);
}
String JOB_ID_VAR = "%job-id%"; //$NON-NLS-1$
String DEFAULT_FILE_NAME = "job.xml"; //$NON-NLS-1$
String DEFAULT_JOB_ID = "job"; //$NON-NLS-1$
@Override
protected InputStream getInitialContents() {
File f = null;
try {
f = new File(BatchUtil.getTemplatesFolder(), DEFAULT_FILE_NAME);
} catch (IOException e) {
BatchCorePlugin.pluginLog().logError(e);
return new ByteArrayInputStream(new byte[0]);
}
String text = FileUtil.readFile(f);
String id = mainPage.idEditor.getValueAsString().trim();
int i = text.indexOf(JOB_ID_VAR);
if(i > 0) {
text = text.substring(0, i) + id + text.substring(i + JOB_ID_VAR.length());
}
return new ByteArrayInputStream(text.getBytes());
}
//Advanced capability is removed.
@Override
protected IStatus validateLinkedResource() {
return Status.OK_STATUS;
}
//Advanced capability is removed.
@Override
protected void createLinkTarget() {
}
@Override
protected void createAdvancedControls(Composite parent) {
Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
GridData sd = new GridData(GridData.FILL_HORIZONTAL);
separator.setLayoutData(sd);
List<String> versions = getVersions();
if(versions.size() > 1) {
//While there is the only Batch version 1.0, this field editor is not created.
versionEditor = SwtFieldEditorFactory.INSTANCE.createComboEditor(BatchConstants.ATTR_VERSION, WizardMessages.versionLabel, versions, getInitialJobVersion(), false, "");
versionEditor.doFillIntoGrid(createComposite(parent));
}
idEditor = SwtFieldEditorFactory.INSTANCE.createTextEditor(BatchConstants.ATTR_ID, WizardMessages.idLabel, DEFAULT_JOB_ID);
idEditor.doFillIntoGrid(createComposite(parent));
idEditor.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if(!isSettingDefaultJobId) {
isJobIdDefault = false;
setPageComplete(validatePage());
}
}
});
}
private Composite createComposite(Composite parent) {
Composite c = new Composite(parent, 0);
c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout gl = new GridLayout(3, false);
gl.marginWidth = 5;
gl.marginHeight = 5;
gl.verticalSpacing = 0;
gl.horizontalSpacing = 5;
c.setLayout(gl);
return c;
}
String getInitialJobVersion() {
return "1.0";
}
List<String> getVersions() {
List<String> versions = new ArrayList<String>();
versions.add(getInitialJobVersion());
//Update when new Batch versions appear.
return versions;
}
Set<String> ids = new HashSet<String>();
IPath lastPath = null;
boolean isJobIdDefault = true;
boolean isSettingDefaultJobId = false;
@Override
protected boolean validatePage() {
boolean valid = super.validatePage();
if(idEditor == null) {
return valid;
}
if(isJobIdDefault) {
String fn = getFileName();
if(fn.endsWith(".xml")) {
fn = fn.substring(0, fn.length() - 4).trim();
}
String id = idEditor.getValueAsString().trim();
if(!id.equals(fn)) {
isSettingDefaultJobId = true;
idEditor.setValue(fn);
isSettingDefaultJobId = false;
}
}
if(valid) {
String id = idEditor.getValueAsString().trim();
if(id.length() == 0) {
setErrorMessage(WizardMessages.errorIdIsRequired);
return false;
}
IPath p = getContainerFullPath();
if(!p.equals(lastPath) && p.segmentCount() > 0) {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(p.segment(0));
if(project != null) {
BatchProject bp = (BatchProject)BatchCorePlugin.getBatchProject(project, true);
if(bp != null) {
ids = new HashSet<String>();
for (BatchJobDefinition def: bp.getDeclaredBatchJobDefinitions()) {
ids.add(def.getJobID());
}
}
}
}
if(ids.contains(id)) {
setMessage(WizardMessages.errorJobIdIsNotUnique, DialogPage.WARNING);
}
}
return valid;
}
}
/**
* Returns path to existing batch-jobs folder that,
* or null, if there is no batch-jobs folder in META-INF folders.
*
* @param p
* @return
*/
public static IPath getBatchJobsContainer(IProject p) {
for (IResource f: EclipseUtil.getJavaSourceRoots(p)) {
if(f instanceof IFolder) {
IFolder fm = ((IFolder)f).getFolder(BatchConstants.META_INF);
IFolder bj = fm.getFolder(BatchConstants.BATCH_JOBS);
if(bj.exists()) {
return bj.getFullPath();
}
}
}
return null;
}
}