blob: 0a0130ec083f59307359690645fd9cda7355c021 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0, which accompanies this distribution
* and is available at https://www.eclipse.org/legal/epl-2.0/.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.jpa.ui.internal.handlers;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
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.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jpt.common.core.resource.xml.JptXmlResource;
import org.eclipse.jpt.common.ui.internal.swt.widgets.DisplayTools;
import org.eclipse.jpt.common.ui.internal.utility.SynchronousUiCommandContext;
import org.eclipse.jpt.common.utility.command.Command;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
import org.eclipse.jpt.common.utility.internal.iterable.TransformationIterable;
import org.eclipse.jpt.common.utility.internal.transformer.TransformerAdapter;
import org.eclipse.jpt.jpa.core.JpaProject;
import org.eclipse.jpt.jpa.core.JpaProjectManager;
import org.eclipse.jpt.jpa.core.context.persistence.Persistence;
import org.eclipse.jpt.jpa.core.context.persistence.PersistenceUnit;
import org.eclipse.jpt.jpa.core.context.persistence.PersistenceXml;
import org.eclipse.jpt.jpa.ui.JptJpaUiMessages;
import org.eclipse.jpt.jpa.ui.internal.plugin.JptJpaUiPlugin;
import org.eclipse.ui.handlers.HandlerUtil;
public class AddToPersistenceUnitHandler extends AbstractHandler
{
private IFile persistenceXmlFile;
public Object execute(ExecutionEvent event) throws ExecutionException {
ISelection selection = HandlerUtil.getCurrentSelectionChecked(event);
for (Map.Entry<IProject, Set<IType>> entry : this.buildSelectedTypes(selection).entrySet()) {
IProject project = entry.getKey();
Set<IType> types = entry.getValue();
JpaProject jpaProject = (JpaProject) project.getAdapter(JpaProject.class);
if (jpaProject != null) {
try {
PersistenceXml persistenceXml = jpaProject.getContextRoot().getPersistenceXml();
if (persistenceXml == null) {
MessageDialog.openInformation(DisplayTools.getShell(), JptJpaUiMessages.ADD_CLASSES_TO_PERSISTENCE_UNIT_MESSAGE_TITLE, JptJpaUiMessages.ADD_CLASSES_TO_PERSISTENCE_UNIT_MESSAGE_TEXT);
} else {
persistenceXmlFile = (IFile) persistenceXml.getResource();
IRunnableWithProgress runnable = new AddClassesRunnable(persistenceXmlFile, convertToTypeNames(types));
this.buildProgressMonitorDialog().run(true, true, runnable); // true => fork; true => cancellable
}
} catch (InvocationTargetException ex) {
JptJpaUiPlugin.instance().logError(ex);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
JptJpaUiPlugin.instance().logError(ex);
}
}
}
return null;
}
protected Iterable<String> convertToTypeNames(Iterable<IType> types) {
return new TransformationIterable<IType, String>(types, new NameTransformer());
}
/* CU private */ class NameTransformer
extends TransformerAdapter<IType, String> {
@Override
public String transform(IType type) {
return type.getFullyQualifiedName('$');
}
}
// ********** selected types **********
/**
* Return a map containing lists of types, keyed by project.
* <p>
* The action is contributed for:<ul>
* <li>{@link IType}
* <li>{@link ICompilationUnit}
* <li>{@link IPackageFragment}
* <li>{@link IPackageFragmentRoot} that is a source folder
* </ul>
*/
private Map<IProject, Set<IType>> buildSelectedTypes(ISelection currentSelection) {
if ( ! (currentSelection instanceof StructuredSelection)) {
return Collections.emptyMap();
}
HashMap<IProject, Set<IType>> types = new HashMap<IProject, Set<IType>>();
for (Object sel : ((StructuredSelection) currentSelection).toList()) {
switch (((IJavaElement) sel).getElementType()) {
case IJavaElement.PACKAGE_FRAGMENT_ROOT :
this.addSelectedTypes((IPackageFragmentRoot) sel, types);
break;
case IJavaElement.PACKAGE_FRAGMENT :
this.addSelectedTypes((IPackageFragment) sel, types);
break;
case IJavaElement.COMPILATION_UNIT :
this.addSelectedTypes((ICompilationUnit) sel, types);
break;
case IJavaElement.TYPE :
this.addSelectedType((IType) sel, types);
break;
default :
break;
}
}
return types;
}
private void addSelectedTypes(IPackageFragmentRoot packageFragmentRoot, Map<IProject, Set<IType>> types) {
for (IJavaElement pkgFragment : this.getPackageFragments(packageFragmentRoot)) {
this.addSelectedTypes((IPackageFragment) pkgFragment, types);
}
}
private void addSelectedTypes(IPackageFragment packageFragment, Map<IProject, Set<IType>> types) {
for (ICompilationUnit compUnit : this.getCompilationUnits(packageFragment)) {
this.addSelectedTypes(compUnit, types);
}
}
private void addSelectedTypes(ICompilationUnit compilationUnit, Map<IProject, Set<IType>> types) {
IType primaryType = compilationUnit.findPrimaryType();
if (primaryType != null) {
this.addSelectedType(primaryType, types);
}
}
private void addSelectedType(IType primaryType, Map<IProject, Set<IType>> typesMap) {
IProject project = primaryType.getJavaProject().getProject();
Set<IType> types = typesMap.get(project);
if (types == null) {
types = new HashSet<IType>();
typesMap.put(project, types);
}
types.add(primaryType);
}
private ICompilationUnit[] getCompilationUnits(IPackageFragment packageFragment) {
try {
return packageFragment.getCompilationUnits();
}
catch (JavaModelException e) {
JptJpaUiPlugin.instance().logError(e);
}
return new ICompilationUnit[0];
}
private IJavaElement[] getPackageFragments(IPackageFragmentRoot packageFragmentRoot) {
try {
return packageFragmentRoot.getChildren();
}
catch (JavaModelException e) {
JptJpaUiPlugin.instance().logError(e);
}
return new IJavaElement[0];
}
private ProgressMonitorDialog buildProgressMonitorDialog() {
return new ProgressMonitorDialog(null);
}
// ********** add classes runnable **********
/**
* This is dispatched to the progress monitor dialog.
*/
/* CU private */ static class AddClassesRunnable implements IRunnableWithProgress
{
private final IFile persistenceXmlFile;
private final Iterable<String> typeNames;
AddClassesRunnable(IFile persistenceXmlFile, Iterable<String> typeNames) {
super();
this.persistenceXmlFile = persistenceXmlFile;
this.typeNames = typeNames;
}
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
this.run_(monitor);
} catch (CoreException ex) {
throw new InvocationTargetException(ex);
}
}
private void run_(IProgressMonitor monitor) throws CoreException {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
// lock the entire project, since we might modify the metamodel classes
ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this.persistenceXmlFile.getProject());
workspace.run(
new AddClassesWorkspaceRunnable(this.persistenceXmlFile, typeNames),
rule,
IWorkspace.AVOID_UPDATE,
monitor
);
}
}
// ********** add classes workspace runnable **********
/**
* This is dispatched to the Eclipse workspace.
*/
/* CU private */ static class AddClassesWorkspaceRunnable implements IWorkspaceRunnable
{
private final IFile persistenceXmlFile;
private final Iterable<String> typeNames;
AddClassesWorkspaceRunnable(IFile persistenceXmlFile, Iterable<String> typeNames) {
super();
this.persistenceXmlFile = persistenceXmlFile;
this.typeNames = typeNames;
}
public void run(IProgressMonitor monitor) throws CoreException {
if (monitor.isCanceled()) {
return;
}
SubMonitor sm = SubMonitor.convert(monitor, JptJpaUiMessages.ADD_CLASSES_TO_PERSISTENCE_UNIT_TASK_NAME, 20);
JpaProject jpaProject = this.getJpaProject();
if (jpaProject == null) {
return;
}
JptXmlResource resource = jpaProject.getPersistenceXmlResource();
if (resource == null) {
// the resource can be null if the persistence.xml file has an invalid content type
return;
}
if (sm.isCanceled()) {
return;
}
sm.worked(1);
PersistenceXml persistenceXml = jpaProject.getContextRoot().getPersistenceXml();
if (persistenceXml == null) {
return; // unlikely...
}
Persistence persistence = persistenceXml.getRoot();
if (persistence == null) {
return; // unlikely...
}
PersistenceUnit persistenceUnit = (persistence.getPersistenceUnitsSize() == 0) ?
persistence.addPersistenceUnit() :
persistence.getPersistenceUnit(0);
if (sm.isCanceled()) {
return;
}
sm.worked(1);
Command addClassesCommand = new AddClassesCommand(persistenceUnit, typeNames, sm.newChild(17));
JpaProjectManager mgr = this.getJpaProjectManager();
try {
if (mgr != null) {
mgr.execute(addClassesCommand, SynchronousUiCommandContext.instance());
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new RuntimeException(ex);
}
resource.save();
sm.worked(1);
}
private JpaProjectManager getJpaProjectManager() {
return (JpaProjectManager) this.getWorkspace().getAdapter(JpaProjectManager.class);
}
private IProject getProject() {
return this.persistenceXmlFile.getProject();
}
private JpaProject getJpaProject() {
return (JpaProject) this.getProject().getAdapter(JpaProject.class);
}
private IWorkspace getWorkspace() {
return this.persistenceXmlFile.getWorkspace();
}
}
// ********** add classes command **********
/**
* This is dispatched to the JPA project manager.
*/
/* CU private */ static class AddClassesCommand implements Command
{
private final PersistenceUnit persistenceUnit;
private final Iterable<String> typeNames;
private final IProgressMonitor monitor;
AddClassesCommand(PersistenceUnit persistenceUnit, Iterable<String> typeNames, IProgressMonitor monitor) {
super();
this.persistenceUnit = persistenceUnit;
this.typeNames = typeNames;
this.monitor = monitor;
}
public void execute() {
this.persistenceUnit.addClasses(typeNames, this.monitor);
}
@Override
public String toString() {
return ObjectTools.toString(this, this.persistenceUnit);
}
}
}