/*******************************************************************************
* Copyright (c) 2007-2009 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
*
* Contributor:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.hibernate.eclipse.jdt.ui.wizards;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.resources.IFile;
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.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.JavaElementInfo;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.PackageFragmentRoot;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.IPageChangingListener;
import org.eclipse.jface.dialogs.PageChangingEvent;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.WizardNewFileCreationPage;
import org.eclipse.ui.ide.IDE;
import org.hibernate.console.ImageConstants;
import org.hibernate.eclipse.console.HibernateConsoleMessages;
import org.hibernate.eclipse.console.HibernateConsolePlugin;
import org.hibernate.eclipse.console.utils.EclipseImages;
import org.hibernate.eclipse.console.utils.FileUtils;
import org.hibernate.eclipse.jdt.ui.internal.JdtUiMessages;
import org.hibernate.eclipse.jdt.ui.internal.jpa.collect.AllEntitiesInfoCollector;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.EntityInfo;
import org.hibernate.eclipse.jdt.ui.internal.jpa.common.Utils;
import org.jboss.tools.hibernate.runtime.spi.IConfiguration;
import org.jboss.tools.hibernate.runtime.spi.IExportPOJODelegate;
import org.jboss.tools.hibernate.runtime.spi.IHibernateMappingExporter;
import org.jboss.tools.hibernate.runtime.spi.IPOJOClass;
import org.jboss.tools.hibernate.runtime.spi.IService;
import org.jboss.tools.hibernate.runtime.spi.ServiceLookup;
/**
* @author Dmitry Geraskov
*
*/
@SuppressWarnings("restriction")
public class NewHibernateMappingFileWizard extends Wizard implements INewWizard, IPageChangingListener{
/**
* Selected compilation units for startup processing,
* result of processing selection
*/
private Set<ICompilationUnit> selectionCU = null;
private Map<IJavaProject, Collection<EntityInfo>> project_infos = new HashMap<IJavaProject, Collection<EntityInfo>>();
private IStructuredSelection selection;
private int processDepth = Integer.MIN_VALUE;
private NewHibernateMappingElementsSelectionPage2 page0 = null;
private WizardNewFileCreationPage cPage;
private NewHibernateMappingFilePage page2 = null;
private NewHibernateMappingPreviewPage previewPage = null;
public NewHibernateMappingFileWizard(){
setDefaultPageImageDescriptor(EclipseImages.getImageDescriptor(ImageConstants.NEW_WIZARD) );
setNeedsProgressMonitor(true);
setWindowTitle(JdtUiMessages.NewHibernateMappingFileWizard_create_hibernate_xml_mapping_file);
}
@Override
public void addPages() {
super.addPages();
if (selection == null) {
selection = new StructuredSelection();
}
page0 = new NewHibernateMappingElementsSelectionPage2(JdtUiMessages.NewHibernateMappingFileWizard_create_hibernate_xml_mapping_file, selection);
page0.setTitle(JdtUiMessages.NewHibernateMappingElementsSelectionPage2_title);
page0.setDescription(JdtUiMessages.NewHibernateMappingElementsSelectionPage2_description);
addPage(page0);
cPage = new WizardNewFileCreationPage( "Ccfgxml", selection ); //$NON-NLS-1$
cPage.setTitle( JdtUiMessages.NewHibernateMappingFileWizard_create_hibernate_xml_mapping_file );
cPage.setDescription( JdtUiMessages.NewHibernateMappingFileWizard_create_empty_xml_mapping_file );
cPage.setFileName("hibernate.hbm.xml"); //$NON-NLS-1$
addPage(cPage);
page2 = new NewHibernateMappingFilePage(false);
page2.setTitle(JdtUiMessages.NewHibernateMappingFilePage_title);
page2.setMessage(JdtUiMessages.NewHibernateMappingFilePage_this_wizard_creates, IMessageProvider.WARNING);
addPage(page2);
previewPage = new NewHibernateMappingPreviewPage();
previewPage.setTitle(JdtUiMessages.NewHibernateMappingPreviewPage_title);
addPage(previewPage);
}
@Override
public IWizardPage getNextPage(IWizardPage page) {
if (page == page0 && !page0.getSelection().isEmpty()) return page2;
if (page == cPage) return null;
return super.getNextPage(page);
}
@Override
public void setContainer(IWizardContainer wizardContainer) {
if (getContainer() instanceof WizardDialog) {
((WizardDialog) getContainer()).removePageChangingListener(this);
}
super.setContainer(wizardContainer);
if (getContainer() instanceof WizardDialog) {
((WizardDialog) getContainer()).addPageChangingListener(this);
}
}
public void handlePageChanging(PageChangingEvent event) {
if (event.getTargetPage() != previewPage) {
// clean up changes
previewPage.setChange(null);
}
if (event.getTargetPage() == page2) {
updateCompilationUnits();
page2.setInput(project_infos);
} else if (event.getTargetPage() == previewPage) {
Map<IJavaProject, IPath> places2Gen = getPlaces2Gen();
previewPage.setPlaces2Gen(places2Gen);
}
}
public void init(IWorkbench workbench, IStructuredSelection selection) {
Set<IJavaElement> filteredElements = new HashSet<IJavaElement>();
Object[] elements = selection.toArray();
for (int i = 0; i < elements.length; i++) {
if (elements[i] instanceof JavaProject) {
JavaProject project = (JavaProject) elements[i];
try {
IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
for (int j = 0; j < roots.length; j++) {
if (!roots[j].isArchive()){
IJavaElement[] rootChildren = roots[j].getChildren();
for (int k = 0; k < rootChildren.length; k++) {
if (rootChildren[k] instanceof IPackageFragment) {
IPackageFragment pkg = (IPackageFragment) rootChildren[k];
try {
if (pkg.containsJavaResources())
filteredElements.add(rootChildren[k]);
} catch (JavaModelException e1) {
e1.printStackTrace();
}
}
}
}
}
} catch (JavaModelException e) {
e.printStackTrace();
}
} else if (elements[i] instanceof IPackageFragmentRoot) {
IPackageFragmentRoot root = (IPackageFragmentRoot)elements[i];
if (!root.isArchive()) {
try {
IJavaElement[] rootChildren = root.getChildren();
for (int k = 0; k < rootChildren.length; k++) {
if (rootChildren[k] instanceof IPackageFragment) {
IPackageFragment pkg = (IPackageFragment) rootChildren[k];
try {
if (pkg.containsJavaResources())
filteredElements.add(rootChildren[k]);
} catch (JavaModelException e1) {
e1.printStackTrace();
}
}
}
} catch (JavaModelException e) {
e.printStackTrace();
}
}
} else if (elements[i] instanceof ICompilationUnit) {
ICompilationUnit cu = (ICompilationUnit)elements[i];
IType[] types;
try {
types = cu.getTypes();
for (int j = 0; j < types.length; j++) {
filteredElements.add(types[j]);
}
} catch (JavaModelException e) {
e.printStackTrace();
}
} else if (elements[i] instanceof IJavaElement) {
filteredElements.add((IJavaElement) elements[i]);
}
}
this.selection = new StructuredSelection(filteredElements.toArray());
}
protected class HibernateMappingExporterWrapper {
protected IJavaProject proj;
private IExportPOJODelegate delegate = new IExportPOJODelegate() {
@Override public void exportPOJO(Map<Object, Object> map, IPOJOClass pojoClass) {
File outputdir4FileOld = target.getOutputDirectory();
File outputdir4FileNew = outputdir4FileOld;
String fullyQualifiedName = pojoClass.getQualifiedDeclarationName();
ICompilationUnit icu = Utils.findCompilationUnit(proj, fullyQualifiedName);
if (icu != null) {
IResource resource = null;
try {
resource = icu.getCorrespondingResource();
} catch (JavaModelException e) {
//ignore
}
String[] aFQName = fullyQualifiedName.split("\\."); //$NON-NLS-1$
int n = aFQName.length - 1;
for ( ; n >= 0 && resource != null; n--) {
if (n == 0 && aFQName[n].length() == 0) {
// handle the (default package) case
break;
}
resource = resource.getParent();
}
if (resource != null) {
final IPath projPath = proj.getResource().getLocation();
IPath place2Gen = previewPage.getRootPlace2Gen().append(proj.getElementName());
IPath tmpPath = resource.getLocation();
tmpPath = tmpPath.makeRelativeTo(projPath);
place2Gen = place2Gen.append(tmpPath);
outputdir4FileNew = place2Gen.toFile();
}
}
if (!outputdir4FileNew.exists()) {
outputdir4FileNew.mkdirs();
}
target.setOutputDirectory(outputdir4FileNew);
target.exportPOJO(map, pojoClass);
target.setOutputDirectory(outputdir4FileOld);
}
};
private IHibernateMappingExporter target = null;
public HibernateMappingExporterWrapper(IJavaProject proj, IConfiguration cfg, File outputdir) {
target = getService(proj).newHibernateMappingExporter(cfg, outputdir);
target.setExportPOJODelegate(delegate);
this.proj = proj;
}
public void start() {
target.start();
}
}
private IService getService(IJavaProject project) {
// Since generating HBM files does not work (yet) with the 5.x runtimes, we always use 3.5 (for now)
// See JBIDE-23066 and JBIDE-21766
/** HibernateNature hibnat = HibernateNature.getHibernateNature(project);
if (hibnat != null) {
ConsoleConfiguration cc = hibnat.getDefaultConsoleConfiguration();
return cc.getHibernateExtension().getHibernateService();
} else {
return ServiceLookup.getDefault();
}
**/
return ServiceLookup.findService("3.5"); //$NON-NLS-1$
}
protected Map<IJavaProject, IPath> getPlaces2Gen() {
updateCompilationUnits();
Map<IJavaProject, IConfiguration> configs = createConfigurations();
Map<IJavaProject, IPath> places2Gen = new HashMap<IJavaProject, IPath>();
for (Entry<IJavaProject, IConfiguration> entry : configs.entrySet()) {
IConfiguration config = entry.getValue();
IPath place2Gen = previewPage.getRootPlace2Gen().append(entry.getKey().getElementName());
places2Gen.put(entry.getKey(), place2Gen);
File folder2Gen = new File(place2Gen.toOSString());
FileUtils.delete(folder2Gen); // cleanup folder before gen info
if (!folder2Gen.exists()) {
folder2Gen.mkdirs();
}
HibernateMappingExporterWrapper hce = new HibernateMappingExporterWrapper(
entry.getKey(), config, folder2Gen);
try {
hce.start();
} catch (Exception e){
HibernateConsolePlugin.getDefault().log(e);
}
}
return places2Gen;
}
protected void cleanUpGenFolders() {
Set<IJavaProject> projs = previewPage.getJavaProjects();
for (IJavaProject proj : projs) {
IPath place2Gen = previewPage.getRootPlace2Gen().append(proj.getElementName());
File folder2Gen = new File(place2Gen.toOSString());
FileUtils.delete(folder2Gen);
}
}
@Override
public boolean performCancel() {
cleanUpGenFolders();
return super.performCancel();
}
@Override
public boolean performFinish() {
boolean res = true;
if (page0.getSelection().isEmpty()){
final IFile file = cPage.createNewFile();
IRunnableWithProgress op = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException {
try {
doFinish(file, monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
}
};
try {
getContainer().run(true, false, op);
} catch (InterruptedException e) {
res = false;
} catch (InvocationTargetException e) {
Throwable realException = e.getTargetException();
HibernateConsolePlugin.getDefault().showError(getShell(), HibernateConsoleMessages.NewReverseEngineeringFileWizard_error, realException);
res = false;
}
cleanUpGenFolders();
} else {
if (previewPage.getChange() == null) {
Map<IJavaProject, IPath> places2Gen = getPlaces2Gen();
previewPage.setPlaces2Gen(places2Gen);
}
previewPage.performFinish();
// refresh
Set<IJavaProject> projs = previewPage.getJavaProjects();
for (IJavaProject proj : projs) {
try {
IPackageFragmentRoot[] pfRoots = proj.getPackageFragmentRoots();
for (int i = 0; i < pfRoots.length; i++) {
IResource container = pfRoots[i].getResource();
if (container != null && container.getType() != IResource.FILE) {
container.refreshLocal(IResource.DEPTH_INFINITE, null);
}
}
} catch (JavaModelException e) {
HibernateConsolePlugin.getDefault().log(e);
} catch (CoreException e) {
HibernateConsolePlugin.getDefault().log(e);
}
}
cleanUpGenFolders();
}
return res;
}
/**
* The worker method. It will find the container, create the
* file if missing or just replace its contents, and open
* the editor on the newly created file.
* @param file
* @param props
*/
private void doFinish(
final IFile file, IProgressMonitor monitor)
throws CoreException {
// create a sample file
monitor.beginTask(HibernateConsoleMessages.NewReverseEngineeringFileWizard_creating + file.getName(), 2);
InputStream stream = null;
try {
stream = openContentStream();
if (file.exists() ) {
file.setContents(stream, true, true, monitor);
} else {
file.create(stream, true, monitor);
}
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// ignore
}
}
}
monitor.worked(1);
monitor.setTaskName(HibernateConsoleMessages.NewConfigurationWizard_open_file_for_editing);
getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
IWorkbenchPage page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
try {
IDE.openEditor(page, file, true);
} catch (PartInitException e) {
HibernateConsolePlugin.getDefault().log(e);
}
}
});
monitor.worked(1);
}
private InputStream openContentStream() {
StringWriter sw = new StringWriter();
sw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //$NON-NLS-1$
"<!DOCTYPE hibernate-mapping PUBLIC \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\" \"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\" >\r\n" + //$NON-NLS-1$
"<hibernate-mapping>\r\n</hibernate-mapping>"); //$NON-NLS-1$
try {
return new ByteArrayInputStream(sw.toString().getBytes("UTF-8") ); //$NON-NLS-1$
} catch (UnsupportedEncodingException uec) {
HibernateConsolePlugin.getDefault().logErrorMessage(HibernateConsoleMessages.NewConfigurationWizard_problems_converting_to_utf8, uec);
return new ByteArrayInputStream(sw.toString().getBytes() );
}
}
protected void initEntitiesInfo(){
if (selectionCU.size() == 0) {
return;
}
AllEntitiesInfoCollector collector = new AllEntitiesInfoCollector();
Iterator<ICompilationUnit> it = selectionCU.iterator();
Map<IJavaProject, Set<ICompilationUnit>> mapJP_CUSet =
new HashMap<IJavaProject, Set<ICompilationUnit>>();
//separate by parent project
while (it.hasNext()) {
ICompilationUnit cu = it.next();
Set<ICompilationUnit> set = mapJP_CUSet.get(cu.getJavaProject());
if (set == null) {
set = new HashSet<ICompilationUnit>();
mapJP_CUSet.put(cu.getJavaProject(), set);
}
set.add(cu);
}
Iterator<Map.Entry<IJavaProject, Set<ICompilationUnit>>>
mapIt = mapJP_CUSet.entrySet().iterator();
while (mapIt.hasNext()) {
Map.Entry<IJavaProject, Set<ICompilationUnit>>
entry = mapIt.next();
IJavaProject javaProject = entry.getKey();
Iterator<ICompilationUnit> setIt = entry.getValue().iterator();
collector.initCollector();
while (setIt.hasNext()) {
ICompilationUnit icu = setIt.next();
collector.collect(icu, processDepth);
}
collector.resolveRelations();
Collection<EntityInfo> c = new ArrayList<EntityInfo>();
for (Iterator<EntityInfo> i = collector.getMapCUs_Info().values().iterator();
i.hasNext();) {
c.add(i.next());
}
project_infos.put(javaProject, c);
}
}
protected void processJavaElements(Object obj, int depth) {
if (depth < 0) {
return;
}
try {
if (obj instanceof ICompilationUnit) {
ICompilationUnit cu = (ICompilationUnit) obj;
selectionCU.add(cu);
} else if (obj instanceof JavaProject && depth > 0) {
JavaProject javaProject = (JavaProject) obj;
IPackageFragmentRoot[] pfr = javaProject.getAllPackageFragmentRoots();
for (IPackageFragmentRoot element : pfr) {
processJavaElements(element, depth - 1);
}
} else if (obj instanceof PackageFragment) {
PackageFragment packageFragment = (PackageFragment) obj;
ICompilationUnit[] cus = packageFragment.getCompilationUnits();
for (ICompilationUnit cu : cus) {
selectionCU.add(cu);
}
} else if (obj instanceof PackageFragmentRoot && depth > 0) {
JavaElement javaElement = (JavaElement) obj;
JavaElementInfo javaElementInfo = (JavaElementInfo) javaElement.getElementInfo();
IJavaElement[] je = javaElementInfo.getChildren();
for (IJavaElement element : je) {
processJavaElements(element, depth - 1);
}
} else if (obj instanceof JavaElement) {
JavaElement javaElement = (JavaElement) obj;
ICompilationUnit cu = javaElement.getCompilationUnit();
selectionCU.add(cu);
}
} catch (JavaModelException e) {
// just ignore it!
//HibernateConsolePlugin.getDefault().logErrorMessage("JavaModelException: ", e); //$NON-NLS-1$
}
}
protected Map<IJavaProject, IConfiguration> createConfigurations() {
ConfigurationActor actor = new ConfigurationActor(selectionCU);
Map<IJavaProject, IConfiguration> configs = actor.createConfigurations(processDepth);
return configs;
}
protected void updateCompilationUnits(){
Assert.isNotNull(page0.getSelection(), JdtUiMessages.NewHibernateMappingFileWizard_selection_cant_be_empty);
if ((selectionCU == null) || !page0.getSelection().equals(selection) ||
processDepth != page0.getProcessDepth()) {
selectionCU = new HashSet<ICompilationUnit>();
project_infos.clear();
selection = page0.getSelection();
processDepth = page0.getProcessDepth();
try {
getContainer().run(false, false, new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws InvocationTargetException,
InterruptedException {
monitor.beginTask(JdtUiMessages.NewHibernateMappingFileWizard_look_for_dependent_cu, selection.size() + 1);
Iterator<?> it = selection.iterator();
int done = 1;
while (it.hasNext()) {
Object obj = it.next();
processJavaElements(obj, processDepth);
monitor.worked(done++);
}
initEntitiesInfo();
monitor.worked(1);
monitor.done();
}
});
} catch (InvocationTargetException e) {
HibernateConsolePlugin.getDefault().log(e);
} catch (InterruptedException e) {
HibernateConsolePlugin.getDefault().log(e);
}
}
}
@Override
public boolean canFinish() {
return !page0.getSelection().isEmpty() || cPage.isPageComplete();
}
}