Java tutorial
/** * Copyright [2014] Gaurav Gupta * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.netbeans.jpa.modeler.jcre.wizard; import java.awt.Window; import java.awt.event.ActionEvent; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JOptionPane; import static javax.swing.JOptionPane.ERROR_MESSAGE; import static javax.swing.JOptionPane.OK_CANCEL_OPTION; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ChangeListener; import org.apache.commons.lang.StringUtils; import org.netbeans.api.progress.aggregate.AggregateProgressFactory; import org.netbeans.api.progress.aggregate.AggregateProgressHandle; import org.netbeans.api.progress.aggregate.ProgressContributor; import org.netbeans.api.project.Project; import org.netbeans.api.templates.TemplateRegistration; import org.netbeans.jpa.modeler._import.javaclass.JCREProcessor; import org.netbeans.jpa.modeler.spec.EntityMappings; import org.netbeans.jpa.modeler.spec.ManagedClass; import org.netbeans.jpa.modeler.spec.extend.IPersistenceAttributes; import org.netbeans.jpa.modeler.spec.extend.RelationAttribute; import org.netbeans.jpa.modeler.specification.model.util.JPAModelerUtil; import static org.netbeans.jpa.modeler.specification.model.util.JPAModelerUtil.getModelerFileVersion; import org.netbeans.jpa.source.JavaSourceParserUtil; import org.netbeans.modeler.core.ModelerFile; import org.netbeans.modeler.core.exception.ProcessInterruptedException; import org.netbeans.modules.j2ee.core.api.support.java.JavaIdentifiers; import org.netbeans.modules.j2ee.persistence.api.EntityClassScope; import org.netbeans.modules.j2ee.persistence.dd.common.PersistenceUnit; import org.netbeans.modules.j2ee.persistence.provider.InvalidPersistenceXmlException; import org.netbeans.modules.j2ee.persistence.provider.ProviderUtil; import org.netbeans.modules.j2ee.persistence.wizard.EntityClosure; import org.netbeans.modules.j2ee.persistence.wizard.PersistenceClientEntitySelection; import org.netbeans.modules.j2ee.persistence.wizard.Util; import org.netbeans.modules.j2ee.persistence.wizard.fromdb.ProgressPanel; import org.netbeans.modules.j2ee.persistence.wizard.jpacontroller.ProgressReporter; import org.netbeans.modules.j2ee.persistence.wizard.jpacontroller.ProgressReporterDelegate; import org.netbeans.modules.j2ee.persistence.wizard.jpacontroller.WizardProperties; import org.netbeans.modules.j2ee.persistence.wizard.unit.PersistenceUnitWizardDescriptor; import org.netbeans.modules.j2ee.persistence.wizard.unit.PersistenceUnitWizardPanel.TableGeneration; import org.netbeans.spi.project.ui.templates.support.Templates; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.WizardDescriptor; import org.openide.awt.NotificationDisplayer; import org.openide.filesystems.FileObject; import org.openide.loaders.DataFolder; import org.openide.util.ImageUtilities; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; import org.openide.util.lookup.ServiceProvider; import org.openide.windows.WindowManager; @ServiceProvider(service = JCREProcessor.class) @TemplateRegistration(folder = "Persistence", position = 2, displayName = "#RevEngWizardDescriptor_displayName", iconBase = "org/netbeans/jpa/modeler/jcre/wizard/resource/JPA_FILE_ICON.png", description = "resource/JPA_JCRE_DESC.html") public final class RevEngWizardDescriptor implements WizardDescriptor.InstantiatingIterator<WizardDescriptor>, JCREProcessor { private int index; private PersistenceUnitWizardDescriptor puPanel; WizardDescriptor wizard; private List<WizardDescriptor.Panel<WizardDescriptor>> panels; private Project project; @Override public Set<?> instantiate() throws IOException { final Set<String> entities = new HashSet<>((List) wizard.getProperty(WizardProperties.ENTITY_CLASS)); if (getProject() == null) { setProject(Templates.getProject(wizard)); } final FileObject packageFileObject = Templates.getTargetFolder(wizard); final String fileName = Templates.getTargetName(wizard); boolean createPersistenceUnit = (Boolean) wizard .getProperty(org.netbeans.modules.j2ee.persistence.wizard.WizardProperties.CREATE_PERSISTENCE_UNIT); if (createPersistenceUnit) { PersistenceUnit punit = Util.buildPersistenceUnitUsingData(getProject(), puPanel.getPersistenceUnitName(), puPanel.getPersistenceConnection() != null ? puPanel.getPersistenceConnection().getName() : puPanel.getDatasource(), TableGeneration.NONE, puPanel.getSelectedProvider()); ProviderUtil.setTableGeneration(punit, puPanel.getTableGeneration(), puPanel.getSelectedProvider()); if (punit != null) { Util.addPersistenceUnitToProject(getProject(), punit); } } final String title = NbBundle.getMessage(RevEngWizardDescriptor.class, "TITLE_Progress_JPA_Model"); //NOI18N return instantiateJCREProcess(title, entities, packageFileObject, fileName, false, true); } private Set<?> instantiateJCREProcess(final String title, final Set<String> entities, final FileObject packageFileObject, final String fileName, boolean includeReference, boolean softWrite) throws IOException { final ProgressContributor progressContributor = AggregateProgressFactory.createProgressContributor(title); final AggregateProgressHandle handle = AggregateProgressFactory.createHandle(title, new ProgressContributor[] { progressContributor }, null, null); final ProgressPanel progressPanel = new ProgressPanel(); final JComponent progressComponent = AggregateProgressFactory.createProgressComponent(handle); final ProgressReporter reporter = new ProgressReporterDelegate(progressContributor, progressPanel); final Runnable r = () -> { try { handle.start(); int progressStepCount = getProgressStepCount(entities.size()); progressContributor.start(progressStepCount); generateJPAModel(reporter, entities, getProject(), packageFileObject, fileName, includeReference, softWrite, true); progressContributor.progress(progressStepCount); } catch (IOException ioe) { Logger.getLogger(RevEngWizardDescriptor.class.getName()).log(Level.INFO, null, ioe); NotifyDescriptor nd = new NotifyDescriptor.Message(ioe.getLocalizedMessage(), NotifyDescriptor.ERROR_MESSAGE); DialogDisplayer.getDefault().notify(nd); } catch (ProcessInterruptedException ce) { Logger.getLogger(RevEngWizardDescriptor.class.getName()).log(Level.INFO, null, ce); } finally { progressContributor.finish(); SwingUtilities.invokeLater(progressPanel::close); handle.finish(); } }; // Ugly hack ensuring the progress dialog opens after the wizard closes. Needed because: // 1) the wizard is not closed in the AWT event in which instantiate() is called. // Instead it is closed in an event scheduled by SwingUtilities.invokeLater(). // 2) when a modal dialog is created its owner is set to the foremost modal // dialog already displayed (if any). Because of #1 the wizard will be // closed when the progress dialog is already open, and since the wizard // is the owner of the progress dialog, the progress dialog is closed too. // The order of the events in the event queue: // - this event // - the first invocation event of our runnable // - the invocation event which closes the wizard // - the second invocation event of our runnable SwingUtilities.invokeLater(new Runnable() { private boolean first = true; @Override public void run() { if (!first) { RequestProcessor.getDefault().post(r); progressPanel.open(progressComponent, title); } else { first = false; SwingUtilities.invokeLater(this); } } }); return Collections.singleton(DataFolder.findFolder(packageFileObject)); } public static int getProgressStepCount(int entityCount) { return entityCount + 2; } public static EntityMappings generateJPAModel(ProgressReporter reporter, Set<String> entities, Project project, FileObject packageFileObject, String fileName) throws IOException, ProcessInterruptedException { return generateJPAModel(reporter, entities, project, packageFileObject, fileName, false, true, true); } public static EntityMappings generateJPAModel(ProgressReporter reporter, Set<String> entities, Project project, FileObject packageFileObject, String fileName, boolean includeReference, boolean softWrite, boolean autoOpen) throws IOException, ProcessInterruptedException { int progressIndex = 0; String progressMsg = NbBundle.getMessage(RevEngWizardDescriptor.class, "MSG_Progress_JPA_Model_Pre"); //NOI18N; reporter.progress(progressMsg, progressIndex++); String version = getModelerFileVersion(); final EntityMappings entityMappingsSpec = EntityMappings.getNewInstance(version); entityMappingsSpec.setGenerated(); if (!entities.isEmpty()) { String entity = entities.iterator().next(); entityMappingsSpec.setPackage(JavaIdentifiers.getPackageName(entity)); } List<String> missingEntities = new ArrayList<>(); for (String entityClass : entities) { progressMsg = NbBundle.getMessage(RevEngWizardDescriptor.class, "MSG_Progress_JPA_Class_Parsing", entityClass + ".java");//NOI18N reporter.progress(progressMsg, progressIndex++); JPAModelGenerator.generateJPAModel(entityMappingsSpec, project, entityClass, packageFileObject, missingEntities); } if (includeReference) { List<ManagedClass> classes = new ArrayList<>(entityMappingsSpec.getEntity()); // manageSiblingAttribute for MappedSuperClass and Embeddable is not required for (DBRE) DB REV ENG CASE classes.addAll(entityMappingsSpec.getMappedSuperclass()); classes.addAll(entityMappingsSpec.getEmbeddable()); for (ManagedClass<IPersistenceAttributes> managedClass : classes) { for (RelationAttribute attribute : new ArrayList<>( managedClass.getAttributes().getRelationAttributes())) { String entityClass = StringUtils.isBlank(entityMappingsSpec.getPackage()) ? attribute.getTargetEntity() : entityMappingsSpec.getPackage() + '.' + attribute.getTargetEntity(); if (!entities.contains(entityClass)) { progressMsg = NbBundle.getMessage(RevEngWizardDescriptor.class, "MSG_Progress_JPA_Class_Parsing", entityClass + ".java");//NOI18N reporter.progress(progressMsg, progressIndex++); JPAModelGenerator.generateJPAModel(entityMappingsSpec, project, entityClass, packageFileObject, missingEntities); entities.add(entityClass); } } } } if (!missingEntities.isEmpty()) { final String title, _package; StringBuilder message = new StringBuilder(); if (missingEntities.size() == 1) { title = "Conflict detected - Entity not found"; message.append(JavaSourceParserUtil.simpleClassName(missingEntities.get(0))).append(" Entity is "); } else { title = "Conflict detected - Entities not found"; message.append("Entities ").append(missingEntities.stream() .map(e -> JavaSourceParserUtil.simpleClassName(e)).collect(toList())).append(" are "); } if (StringUtils.isEmpty(entityMappingsSpec.getPackage())) { _package = "<default_root_package>"; } else { _package = entityMappingsSpec.getPackage(); } message.append("missing in Project classpath[").append(_package) .append("]. \n Would like to cancel the process ?"); SwingUtilities.invokeLater(() -> { JButton cancel = new JButton("Cancel import process (Recommended)"); JButton procced = new JButton("Procced"); cancel.addActionListener((ActionEvent e) -> { Window w = SwingUtilities.getWindowAncestor(cancel); if (w != null) { w.setVisible(false); } StringBuilder sb = new StringBuilder(); sb.append('\n').append("You have following option to resolve conflict :").append('\n') .append('\n'); sb.append( "1- New File > Persistence > JPA Diagram from Reverse Engineering (Manually select entities)") .append('\n'); sb.append( "2- Recover missing entities manually > Reopen diagram file > Import entities again"); NotifyDescriptor nd = new NotifyDescriptor.Message(sb.toString(), NotifyDescriptor.INFORMATION_MESSAGE); DialogDisplayer.getDefault().notify(nd); }); procced.addActionListener((ActionEvent e) -> { Window w = SwingUtilities.getWindowAncestor(cancel); if (w != null) { w.setVisible(false); } manageEntityMappingspec(entityMappingsSpec); JPAModelerUtil.createNewModelerFile(entityMappingsSpec, packageFileObject, fileName, softWrite, autoOpen); }); JOptionPane.showOptionDialog(WindowManager.getDefault().getMainWindow(), message.toString(), title, OK_CANCEL_OPTION, ERROR_MESSAGE, UIManager.getIcon("OptionPane.errorIcon"), new Object[] { cancel, procced }, cancel); }); } else { manageEntityMappingspec(entityMappingsSpec); JPAModelerUtil.createNewModelerFile(entityMappingsSpec, packageFileObject, fileName, softWrite, autoOpen); return entityMappingsSpec; } throw new ProcessInterruptedException(); } private static void manageEntityMappingspec(EntityMappings entityMappingsSpec) { entityMappingsSpec.manageRefId(); entityMappingsSpec.repairDefinition(JPAModelerUtil.IO, true); // entityMappingsSpec.manageJoinColumnRefName(); } @Override public void initialize(WizardDescriptor wizard) { this.wizard = wizard; index = 0; // obtaining target folder if (getProject() == null) { setProject(Templates.getProject(wizard)); } WizardDescriptor.Panel secondPanel = new ValidationPanel(getProject(), new PersistenceClientEntitySelection( NbBundle.getMessage(RevEngWizardDescriptor.class, "LBL_EntityClasses"), null, wizard)); // NOI18N WizardDescriptor.Panel thirdPanel = new JPAModelSetupPanel(getProject(), wizard); String names[]; boolean noPuNeeded = true; try { noPuNeeded = ProviderUtil.persistenceExists(getProject()) || !ProviderUtil.isValidServerInstanceOrNone(project); } catch (InvalidPersistenceXmlException ex) { Logger.getLogger(RevEngWizardDescriptor.class.getName()).log(Level.FINE, "Invalid persistence.xml: {0}", ex.getPath()); //NOI18N } if (!noPuNeeded) { puPanel = new PersistenceUnitWizardDescriptor(getProject()); panels = new ArrayList<WizardDescriptor.Panel<WizardDescriptor>>(); panels.add(secondPanel); panels.add(thirdPanel); panels.add(puPanel); names = new String[] { NbBundle.getMessage(RevEngWizardDescriptor.class, "LBL_EntityClasses"), NbBundle.getMessage(RevEngWizardDescriptor.class, "LBL_JPA_Model"), NbBundle.getMessage(RevEngWizardDescriptor.class, "LBL_PersistenceUnitSetup") }; } else { panels = new ArrayList<WizardDescriptor.Panel<WizardDescriptor>>(); panels.add(secondPanel); panels.add(thirdPanel); names = new String[] { NbBundle.getMessage(RevEngWizardDescriptor.class, "LBL_EntityClasses"), NbBundle.getMessage(RevEngWizardDescriptor.class, "LBL_JPA_Model") }; } wizard.putProperty("NewFileWizard_Title", NbBundle.getMessage(RevEngWizardDescriptor.class, "NewFileWizard_Title_JPAModelFromEntities")); org.netbeans.modeler.component.Wizards.mergeSteps(wizard, panels.toArray(new WizardDescriptor.Panel[0]), names); } @Override public void uninitialize(WizardDescriptor wizard) { panels = null; } @Override public WizardDescriptor.Panel current() { return panels.get(index); } @Override public String name() { return NbBundle.getMessage(RevEngWizardDescriptor.class, "LBL_WizardTitle_FromEntity"); } @Override public boolean hasNext() { return index < panels.size() - 1; } @Override public boolean hasPrevious() { return index > 0; } @Override public void nextPanel() { if (!hasNext()) { throw new NoSuchElementException(); } index++; } @Override public void previousPanel() { if (!hasPrevious()) { throw new NoSuchElementException(); } index--; } @Override public void addChangeListener(ChangeListener l) { } @Override public void removeChangeListener(ChangeListener l) { } @Override public void process(ModelerFile file) { try { this.setProject(file.getProject()); EntityMappings entityMappings = (EntityMappings) file.getDefinitionElement(); FileObject packageFileObject = file.getFileObject().getParent(); String fileName = file.getFileObject().getName(); Set<String> entities = entityMappings.getEntity().stream() .map(e -> StringUtils.isBlank(entityMappings.getPackage()) ? e.getClazz() : entityMappings.getPackage() + "." + e.getClazz()) .collect(toSet()); EntityClassScope entityClassScope = EntityClassScope.getEntityClassScope(project.getProjectDirectory()); EntityClosure entityClosure = EntityClosure.create(entityClassScope, project); entityClosure.setClosureEnabled(true); entityClosure.addEntities(entities); if (entityClosure.getSelectedEntities().size() > entities.size()) { javax.swing.JOptionPane.showInputDialog("Entity closure have more entity"); } String backupFileName = fileName + "_backup"; FileObject backupFile = null; try { backupFile = org.openide.filesystems.FileUtil.copyFile(file.getFileObject(), packageFileObject, backupFileName); } catch (Exception ex) { } instantiateJCREProcess("Updating Design", entities, packageFileObject, fileName, true, false); notifyBackupCreation(file, backupFile); } catch (IOException ex) { file.handleException(ex); } } private static void notifyBackupCreation(ModelerFile file, FileObject backupFile) { if (backupFile == null) { return; } NotificationDisplayer.getDefault().notify("Backup created", ImageUtilities.image2Icon(file.getIcon()), // ImageUtilities.loadImageIcon("org/netbeans/jpa/modeler/specification/model/file/JPA_FILE_ICON.png", false), "Previous state of file has been saved to " + backupFile.getName() + ". Click here to delete it", (ActionEvent e) -> { try { if (backupFile.isValid()) { backupFile.delete(); } } catch (IOException ex) { file.handleException(ex); } }, NotificationDisplayer.Priority.NORMAL, NotificationDisplayer.Category.INFO); } /** * A panel which checks that the target project has a valid server set * otherwise it delegates to the real panel. */ private static class ValidationPanel extends DelegatingWizardDescriptorPanel { private ValidationPanel(Project project, WizardDescriptor.Panel delegate) { super(project, delegate); } } /** * @return the project */ public Project getProject() { return project; } /** * @param project the project to set */ public void setProject(Project project) { this.project = project; } }