/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.mappingsplugin;
import java.awt.EventQueue;
import java.awt.Frame;
import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import javax.swing.Action;
import javax.swing.JOptionPane;
import org.eclipse.persistence.tools.workbench.framework.action.AbstractFrameworkAction;
import org.eclipse.persistence.tools.workbench.framework.app.ApplicationNode;
import org.eclipse.persistence.tools.workbench.framework.context.WorkbenchContext;
import org.eclipse.persistence.tools.workbench.framework.resources.ResourceRepository;
import org.eclipse.persistence.tools.workbench.framework.ui.chooser.MultipleClassChooserDialog;
import org.eclipse.persistence.tools.workbench.framework.ui.dialog.WaitDialog;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWError;
import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.DescriptorCreationFailureContainer;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.ExternalClassLoadFailureContainer;
import org.eclipse.persistence.tools.workbench.mappingsmodel.meta.MWClassRepository;
import org.eclipse.persistence.tools.workbench.mappingsmodel.project.MWProject;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.common.StatusDialog;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.common.cell.ProjectCellRendererAdapter;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.descriptor.DescriptorCreationFailuresDialog;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.meta.ExternalClassDescriptionClassDesciptionAdapter;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.meta.ExternalClassDescriptionClassDescriptionRepository;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.meta.ExternalClassLoadFailuresDialog;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.project.ProjectNode;
import org.eclipse.persistence.tools.workbench.mappingsplugin.ui.project.UiProjectBundle;
import org.eclipse.persistence.tools.workbench.uitools.cell.CellRendererAdapter;
import org.eclipse.persistence.tools.workbench.utility.Classpath;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
/**
* import classes from the external class repository,
* adding or refreshing as appropriate
*/
public final class AddOrRefreshClassesAction
extends AbstractFrameworkAction
{
public static final String EJB_JAR_XML_EXCEPTION_ERROR = "EJB_JAR_XML_EXCEPTION_ERROR";
public static final String EJB_JAR_XML_PROJECT_NOT_UPDATED_ERROR = "EJB_JAR_XML_PROJECT_NOT_UPDATED_ERROR";
public static final String INVALID_DOC_TYPE_ERROR = "INVALID_DOC_TYPE_ERROR";
AddOrRefreshClassesAction(WorkbenchContext context) {
super(context.buildExpandedResourceRepositoryContext(UiProjectBundle.class));
}
protected void initialize() {
super.initialize();
this.initializeIcon("descriptor.refresh");
this.initializeTextAndMnemonic("ADD_OR_REFRESH_CLASSES_ACTION");
this.initializeToolTipText("ADD_OR_REFRESH_CLASSES_ACTION.toolTipText");
this.initializeAccelerator("ADD_OR_REFRESH_CLASSES_ACTION.accelerator");
}
protected void execute() {
ApplicationNode[] projectNodes = this.selectedProjectNodes();
for (int i = 0; i < projectNodes.length; i++) {
this.execute((ProjectNode) projectNodes[i]);
}
}
/**
* prompt the user for classes, then check for any errors;
* if we have an EJB project, prompt the user to update from ejb-jar.xml
*/
protected void execute(ProjectNode projectNode) {
MWProject project = projectNode.getProject();
// Do NOT automatically refresh the types when opening the multiple class chooser dialog.
// Allow the user to control when the list of available types is refreshed, with the <Refresh> button.
// @see MWClassRepository.refreshExternalClassDescriptions()
MultipleClassChooserDialog dialog = this.buildDialog(project.getRepository());
dialog.show();
if (dialog.wasConfirmed()) {
this.startClassImporter(project, CollectionTools.collection(dialog.selectedClassDescriptions()));
}
// try to force all the objects generated by the dialog to be garbage-collected
dialog = null;
MultipleClassChooserDialog.gc();
}
/**
* display only the classes found on the "project" classpath
*/
private MultipleClassChooserDialog buildDialog(MWClassRepository repository) {
return new MultipleClassChooserDialog(
this.getWorkbenchContext(),
new LocalClassDescriptionRepository(repository),
ExternalClassDescriptionClassDesciptionAdapter.instance()
);
}
/**
* Start a thread that will import classes from class files
*/
private void startClassImporter(MWProject project, Collection selectedClassDescriptions) {
Thread thread = new Thread(new ClassImporter(project, selectedClassDescriptions), "Class Import");
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
// ********** inner classes **********
/**
* tweak the external class description repos to only return the classes found on
* the "project" classpath
*/
private class LocalClassDescriptionRepository extends ExternalClassDescriptionClassDescriptionRepository {
Set userClassNames;
LocalClassDescriptionRepository(MWClassRepository repository) {
super(repository);
Classpath cp = new Classpath(CollectionTools.list(repository.fullyQualifiedClasspathEntries()));
this.userClassNames = new HashSet(1000); // start sorta big
cp.addClassNamesTo(this.userClassNames);
}
protected boolean accept(String externalClassDescriptionName) {
return super.accept(externalClassDescriptionName) &&
this.userClassNames.contains(externalClassDescriptionName);
}
}
/**
* display a "wait" dialog while the classes are being imported
*/
private class ClassImporter implements Runnable {
private MWProject project;
private Collection selectedClassDescriptions;
ClassImporter(MWProject project, Collection selectedClassDescriptions) {
super();
this.project = project;
this.selectedClassDescriptions = selectedClassDescriptions;
}
public void run() {
WaitDialog waitDialog = this.buildWaitDialog();
launchLater(waitDialog);
DescriptorCreationFailureContainer descriptorFailures = new DescriptorCreationFailureContainer();
// pause the validator to improve performance on large imports
this.project.getValidator().pause();
ExternalClassLoadFailureContainer classFailures;
try {
classFailures = this.project.addDescriptorsForExternalClassDescriptions(this.selectedClassDescriptions.iterator(), descriptorFailures);
} finally {
// if we don't resume the validator, things will be really whacked...
this.project.getValidator().resume();
waitDialog.dispose();
}
if (classFailures.containsFailures()) {
launchAndWait(new ExternalClassLoadFailuresDialog(this.workbenchContext(), classFailures));
}
if (descriptorFailures.containsFailures()) {
launchAndWait(new DescriptorCreationFailuresDialog(descriptorFailures, this.workbenchContext()));
}
// TODO expand the project/package nodes and select one of the new classes?
}
private WaitDialog buildWaitDialog() {
return new WaitDialog(
(Frame) this.workbenchContext().getCurrentWindow(),
this.resourceRepository().getIcon("class.default"),
this.resourceRepository().getString("CLASS_IMPORT_WAIT_DIALOG.TITLE"),
this.resourceRepository().getString("CLASS_IMPORT_WAIT_MESSAGE")
);
}
private boolean promptUserToUpdateProjectFromEjbJarXml() {
class Prompt implements Runnable {
int option = 0;
public void run() {
this.option = JOptionPane.showConfirmDialog(
ClassImporter.this.workbenchContext().getCurrentWindow(),
ClassImporter.this.resourceRepository().getString("UPDATE_PROJECT_FROM_EJB_JAR"),
ClassImporter.this.resourceRepository().getString("UPDATE_PROJECT_FROM_EJB_JAR.title"),
JOptionPane.YES_NO_OPTION
);
}
}
Prompt prompt = new Prompt();
try {
EventQueue.invokeAndWait(prompt);
} catch (Throwable t) {
throw new RuntimeException(t);
}
return prompt.option == JOptionPane.YES_OPTION;
}
private boolean canReadWithProblems(LinkedHashMap problems) {
StatusDialog.Status status = StatusDialog.createStatus(this.project, problems);
StatusDialog dialog = new LocalStatusDialog(Collections.singleton(status));
launchAndWait(dialog);
return dialog.wasConfirmed();
}
private void showEJBResult(Collection results) {
if (results.isEmpty()) {
return;
}
StatusDialog dialog = new StatusDialog(
this.workbenchContext(),
results,
"PROJECT_EJB_UPDATE_STATUS_DIALOG_TITLE",
"PROJECT_EJB_UPDATE_STATUS_DIALOG_MESSAGE",
"project.export.ejb-jar.xml")
{
protected CellRendererAdapter buildNodeRenderer(Object value) {
if (value instanceof MWProject) {
return new ProjectCellRendererAdapter(ClassImporter.this.resourceRepository());
}
return super.buildNodeRenderer(value);
}
};
launchAndWait(dialog);
}
WorkbenchContext workbenchContext() {
return AddOrRefreshClassesAction.this.getWorkbenchContext();
}
ResourceRepository resourceRepository() {
return AddOrRefreshClassesAction.this.resourceRepository();
}
}
/**
* display EJB project update "status"???
*/
private class LocalStatusDialog extends StatusDialog {
private LocalStatusDialog(Collection projectStatus) {
super(AddOrRefreshClassesAction.this.getWorkbenchContext(),
projectStatus,
"PROJECT_EJB_UPDATE_STATUS_DIALOG_TITLE",
"PROJECT_UPDATE_STATUS_DIALOG_MESSAGE",
"project.export.ejb-jar.xml");
}
protected Action buildOKAction() {
Action action = super.buildOKAction();
action.putValue(Action.NAME, this.resourceRepository().getString("EJB_JAR_XML_VALIDATOR_STATUS_DIALOG_YES_BUTTON"));
action.putValue(Action.MNEMONIC_KEY, new Integer(this.resourceRepository().getMnemonic("EJB_JAR_XML_VALIDATOR_STATUS_DIALOG_YES_BUTTON")));
return action;
}
protected Action buildCancelAction() {
Action action = super.buildCancelAction();
action.putValue(Action.NAME, this.resourceRepository().getString("EJB_JAR_XML_VALIDATOR_STATUS_DIALOG_NO_BUTTON"));
action.putValue(Action.MNEMONIC_KEY, new Integer(this.resourceRepository().getMnemonic("EJB_JAR_XML_VALIDATOR_STATUS_DIALOG_NO_BUTTON")));
return action;
}
protected boolean cancelButtonIsVisible() {
return true;
}
protected CellRendererAdapter buildNodeRenderer(Object value) {
if (value instanceof MWProject) {
return new ProjectCellRendererAdapter(this.resourceRepository());
}
return super.buildNodeRenderer(value);
}
}
}