diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVault.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVault.java index dc0bba1aee65..e4d0dc0eb6ae 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVault.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/AddDbConnectionToVault.java @@ -31,12 +31,6 @@ import com.oracle.bmc.devops.responses.GetDeployArtifactResponse; import com.oracle.bmc.devops.responses.ListDeployArtifactsResponse; import com.oracle.bmc.devops.responses.ListProjectsResponse; -import com.oracle.bmc.identity.Identity; -import com.oracle.bmc.identity.IdentityClient; -import com.oracle.bmc.identity.model.Compartment; -import com.oracle.bmc.identity.requests.ListCompartmentsRequest; -import com.oracle.bmc.identity.responses.ListCompartmentsResponse; -import com.oracle.bmc.identity.model.Tenancy; import org.netbeans.api.db.explorer.DatabaseConnection; import com.oracle.bmc.model.BmcException; import com.oracle.bmc.vault.VaultsClient; @@ -60,16 +54,12 @@ import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import java.util.Optional; import java.util.Set; -import java.util.TreeMap; import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; @@ -77,23 +67,26 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.project.Project; import org.netbeans.modules.cloud.oracle.OCIManager; import static org.netbeans.modules.cloud.oracle.OCIManager.getDefault; -import org.netbeans.modules.cloud.oracle.OCIProfile; -import org.netbeans.modules.cloud.oracle.OCISessionInitiator; +import org.netbeans.modules.cloud.oracle.assets.DependencyUtils; +import org.netbeans.modules.cloud.oracle.assets.Steps; +import org.netbeans.modules.cloud.oracle.assets.Step; +import org.netbeans.modules.cloud.oracle.assets.Steps.NextStepProvider; +import org.netbeans.modules.cloud.oracle.assets.Steps.ProjectStep; +import org.netbeans.modules.cloud.oracle.assets.Steps.TenancyStep; import org.netbeans.modules.cloud.oracle.compartment.CompartmentItem; import org.netbeans.modules.cloud.oracle.devops.DevopsProjectItem; import org.netbeans.modules.cloud.oracle.devops.DevopsProjectService; import org.netbeans.modules.cloud.oracle.items.OCID; import org.netbeans.modules.cloud.oracle.items.OCIItem; -import org.netbeans.modules.cloud.oracle.items.TenancyItem; import org.netbeans.modules.cloud.oracle.vault.KeyItem; import org.netbeans.modules.cloud.oracle.vault.KeyNode; import org.netbeans.modules.cloud.oracle.vault.SecretItem; import org.netbeans.modules.cloud.oracle.vault.SecretNode; import org.netbeans.modules.cloud.oracle.vault.VaultItem; import org.netbeans.modules.cloud.oracle.vault.VaultNode; -import org.openide.DialogDescriptor; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.NotifyDescriptor.QuickPick.Item; @@ -101,8 +94,10 @@ import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; import org.openide.awt.ActionRegistration; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.Pair; +import org.openide.util.lookup.Lookups; /** * @@ -152,149 +147,14 @@ public AddDbConnectionToVault(DatabaseConnection context) { this.context = context; } - static interface Step { - - Step prepare(T item); - - NotifyDescriptor createInput(); - - boolean onlyOneChoice(); - - Step getNext(); - - void setValue(String selected); - - U getValue(); - } - - class TenancyStep implements Step { - - List profiles = new LinkedList<>(); - private AtomicReference selected = new AtomicReference<>(); - - @Override - public NotifyDescriptor createInput() { - if (onlyOneChoice()) { - throw new IllegalStateException("No data to create input"); // NOI18N - } - String title = Bundle.SelectProfile(); - List items = new ArrayList<>(profiles.size()); - for (OCIProfile p : profiles) { - Tenancy t = p.getTenancyData(); - if (t != null) { - items.add(new NotifyDescriptor.QuickPick.Item(p.getId(), Bundle.SelectProfile_Description(t.getName(), t.getHomeRegionKey()))); - } - } - if (profiles.stream().filter(p -> p.getTenancy().isPresent()).count() == 0) { - title = Bundle.NoProfile(); - } - return new NotifyDescriptor.QuickPick(title, title, items, false); - } - - @Override - public Step getNext() { - return new CompartmentStep().prepare(getValue()); - } - - public Step prepare(Object i) { - ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingProfiles()); - h.start(); - h.progress(Bundle.MSG_CollectingProfiles_Text()); - try { - profiles = OCIManager.getDefault().getConnectedProfiles(); - } finally { - h.finish(); - } - return this; - } - - public void setValue(String value) { - for (OCIProfile profile : profiles) { - if (profile.getId().equals(value)) { - profile.getTenancy().ifPresent(t -> this.selected.set(t)); - OCIManager.getDefault().setActiveProfile(profile); - break; - } - } - } - - @Override - public TenancyItem getValue() { - if (onlyOneChoice()) { - return profiles.stream() - .map(p -> p.getTenancy()) - .filter(Optional::isPresent) - .map(Optional::get) - .findFirst() - .get(); - } - return selected.get(); - } - - @Override - public boolean onlyOneChoice() { - return profiles.stream().filter(p -> p.getTenancy().isPresent()).count() == 1; - } - } - - class CompartmentStep implements Step { - - private Map compartments = null; - private CompartmentItem selected; - - public Step prepare(TenancyItem tenancy) { - ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingItems()); - h.start(); - h.progress(Bundle.MSG_CollectingItems_Text()); - try { - compartments = getFlatCompartment(tenancy); - } finally { - h.finish(); - } - return this; - } - - @Override - public NotifyDescriptor createInput() { - if (onlyOneChoice()) { - throw new IllegalStateException("Input shouldn't be displayed for one choice"); // NOI18N - } - if (compartments.isEmpty()) { - createQuickPick(compartments, Bundle.NoCompartment()); - } - return createQuickPick(compartments, Bundle.SelectCompartment()); - } - - @Override - public Step getNext() { - return new VaultStep().prepare(getValue()); - } - - @Override - public void setValue(String selected) { - this.selected = (CompartmentItem) compartments.get(selected); - } - - @Override - public CompartmentItem getValue() { - if (onlyOneChoice()) { - return (CompartmentItem) compartments.values().iterator().next(); - } - return selected; - } - - @Override - public boolean onlyOneChoice() { - return compartments.size() == 1; - } - } - class VaultStep implements Step { private Map vaults = null; private VaultItem selected; + private Lookup lookup; - public Step prepare(CompartmentItem compartment) { + public Step prepare(CompartmentItem compartment, Lookup lookup) { + this.lookup = lookup; ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingItems()); h.start(); h.progress(Bundle.MSG_CollectingItems_Text()); @@ -313,7 +173,7 @@ public NotifyDescriptor createInput() { @Override public Step getNext() { - return new KeyStep().prepare(getValue()); + return new KeyStep().prepare(getValue(), lookup); } @Override @@ -340,9 +200,11 @@ class KeyStep implements Step> { private Map keys = null; private KeyItem selected; private VaultItem vault; + private Lookup lookup; - public Step> prepare(VaultItem vault) { + public Step> prepare(VaultItem vault, Lookup lookup) { this.vault = vault; + this.lookup = lookup; ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingItems()); h.start(); h.progress(Bundle.MSG_CollectingItems_Text()); @@ -373,7 +235,7 @@ public NotifyDescriptor createInput() { @Override public Step getNext() { - return new DatasourceNameStep().prepare(getValue()); + return new DatasourceNameStep().prepare(getValue(), lookup); } @Override @@ -394,9 +256,11 @@ public Pair getValue() { class DatasourceNameStep implements Step, Result> { private Result result = new Result(); + private Lookup lookup; @Override - public Step, Result> prepare(Pair item) { + public Step, Result> prepare(Pair item, Lookup lookup) { + this.lookup = lookup; result.vault = item.first(); result.key = item.second(); return this; @@ -409,7 +273,7 @@ public NotifyDescriptor createInput() { @Override public Step getNext() { - return new OverwriteStep().prepare(result); + return new OverwriteStep().prepare(result, lookup); } @Override @@ -434,9 +298,11 @@ class OverwriteStep implements Step { private Result result; private Set dsNames; private String choice; + private Lookup lookup; @Override - public Step prepare(Result result) { + public Step prepare(Result result, Lookup lookup) { + this.lookup = lookup; this.result = result; if (result.datasourceName == null || result.datasourceName.isEmpty()) { return this; @@ -462,7 +328,7 @@ public NotifyDescriptor createInput() { @Override public Step getNext() { - return new PasswordStep().prepare(result); + return new PasswordStep().prepare(result, lookup); } @Override @@ -487,12 +353,13 @@ public boolean onlyOneChoice() { } class PasswordStep implements Step { - private Result item; private boolean ask; + private Lookup lookup; @Override - public Step prepare(Result item) { + public Step prepare(Result item, Lookup lookup) { + this.lookup = lookup; item.password = context.getPassword(); ask = item.password == null || item.password.isEmpty(); this.item = item; @@ -511,7 +378,7 @@ public boolean onlyOneChoice() { @Override public Step getNext() { - return new DevopsStep().prepare(item); + return new DevopsStep().prepare(item, lookup); } @Override @@ -526,13 +393,14 @@ public Result getValue() { } class DevopsStep implements Step { - private Result item; private Map devopsProjects; + private Lookup lookup; @Override - public Step prepare(Result item) { + public Step prepare(Result item, Lookup lookup) { this.item = item; + this.lookup = lookup; ProgressHandle h = ProgressHandle.createHandle(Bundle.MSG_CollectingItems()); h.start(); h.progress(Bundle.MSG_CollectingItems_Text()); @@ -578,6 +446,13 @@ public boolean onlyOneChoice() { @Override public Step getNext() { + NextStepProvider nsProvider = lookup.lookup(NextStepProvider.class); + if (nsProvider != null) { + Step ns = nsProvider.nextStepFor(this); + if (ns != null) { + return ns.prepare(getValue(), lookup); + } + } return null; } @@ -592,7 +467,7 @@ public Result getValue() { } } - static class Result { + static final class Result { VaultItem vault; KeyItem key; String datasourceName; @@ -600,93 +475,27 @@ static class Result { DevopsProjectItem project; private boolean update; } - - static class Multistep { - - private final LinkedList steps = new LinkedList<>(); - - Multistep(Step firstStep) { - steps.add(firstStep); - } - - NotifyDescriptor.ComposedInput.Callback createInput() { - return new NotifyDescriptor.ComposedInput.Callback() { - private int lastNumber = 0; - - private void readValue(Step step, NotifyDescriptor desc) { - String selected = null; - if (!step.onlyOneChoice()) { - if (desc instanceof NotifyDescriptor.QuickPick) { - for (NotifyDescriptor.QuickPick.Item item : ((NotifyDescriptor.QuickPick) desc).getItems()) { - if (item.isSelected()) { - selected = item.getLabel(); - break; - } - } - } else if (desc instanceof NotifyDescriptor.InputLine) { - selected = ((NotifyDescriptor.InputLine) desc).getInputText(); - } - step.setValue(selected); - } - } - - @Override - public NotifyDescriptor createInput(NotifyDescriptor.ComposedInput input, int number) { - if (number == 1) { - while (steps.size() > 1) { - steps.removeLast(); - } - steps.getLast().prepare(null); - } else if (lastNumber > number) { - steps.removeLast(); - while(steps.getLast().onlyOneChoice() && steps.size() > 1) { - steps.removeLast(); - } - lastNumber = number; - return steps.getLast().createInput(); - } else { - readValue(steps.getLast(), input.getInputs()[number - 2]); - steps.add(steps.getLast().getNext()); - } - lastNumber = number; - - while(steps.getLast() != null && steps.getLast().onlyOneChoice()) { - steps.add(steps.getLast().getNext()); - } - if (steps.getLast() == null) { - steps.removeLast(); - return null; - } - return steps.getLast().createInput(); - } - }; - } - - Object getResult() { - return steps.getLast().getValue(); - } - } - + @Override public void actionPerformed(ActionEvent e) { - Multistep multistep = new Multistep(new TenancyStep()); - - NotifyDescriptor.ComposedInput ci = new NotifyDescriptor.ComposedInput(Bundle.AddADBToVault(), 3, multistep.createInput()); - if (DialogDescriptor.OK_OPTION == DialogDisplayer.getDefault().notify(ci)) { - if (multistep.getResult() != null) { - Result result = (Result) multistep.getResult(); - if (result.datasourceName == null || result.datasourceName.isEmpty()) { + NextStepProvider nsProvider = NextStepProvider.builder() + .stepForClass(Steps.CompartmentStep.class, (s) -> new VaultStep()) + .stepForClass(DevopsStep.class, (s) -> new ProjectStep()) + .build(); + Lookup lookup = Lookups.fixed(nsProvider); + Steps.getDefault().executeMultistep(new TenancyStep(), lookup).thenAccept(r -> { + Result result = ((Pair) r).second(); + Project project = ((Pair) r).first(); + if (result.datasourceName == null || result.datasourceName.isEmpty()) { NotifyDescriptor.Message msg = new NotifyDescriptor.Message(Bundle.DatasourceEmpty()); DialogDisplayer.getDefault().notify(msg); return; } - addDbConnectionToVault(result); - } - } - + addDbConnectionToVault(result, project); + }); } - private void addDbConnectionToVault(Result item) { + private void addDbConnectionToVault(Result item, Project project) { ProgressHandle h = ProgressHandle.createHandle(Bundle.UpdatingVault(item.vault.getName())); h.start(); h.progress(Bundle.ReadingSecrets()); @@ -755,7 +564,14 @@ private void addDbConnectionToVault(Result item) { client.createSecret(request); } } - + + // Add Vault dependency to the project + try { + DependencyUtils.addDependency(project, "io.micronaut.oraclecloud", "micronaut-oraclecloud-vault"); + } catch (IllegalStateException e) { + LOG.log(Level.INFO, "Unable to add Vault dependency", e); + } + // Add Vault to the ConfigMap artifact DevopsClient devopsClient = DevopsClient.builder().build(OCIManager.getDefault().getActiveProfile().getConfigProvider()); ListDeployArtifactsRequest request = ListDeployArtifactsRequest.builder() @@ -908,78 +724,6 @@ private static NotifyDescriptor.QuickPick createQuickPick(Ma return new NotifyDescriptor.QuickPick(title, title, items, false); } - private static Map getFlatCompartment(TenancyItem tenancy) { - Map compartments = new HashMap<>(); - OCISessionInitiator session = OCIManager.getDefault().getActiveSession(); - Identity identityClient = session.newClient(IdentityClient.class); - String nextPageToken = null; - - do { - ListCompartmentsResponse response - = identityClient.listCompartments( - ListCompartmentsRequest.builder() - .compartmentId(tenancy.getKey().getValue()) - .compartmentIdInSubtree(true) - .lifecycleState(Compartment.LifecycleState.Active) - .accessLevel(ListCompartmentsRequest.AccessLevel.Accessible) - .limit(1000) - .page(nextPageToken) - .build()); - for (Compartment comp : response.getItems()) { - FlatCompartmentItem ci = new FlatCompartmentItem(comp) { - FlatCompartmentItem getItem(OCID compId) { - return compartments.get(compId); - } - }; - compartments.put(ci.getKey(), ci); - } - nextPageToken = response.getOpcNextPage(); - } while (nextPageToken != null); - Map pickItems = computeFlatNames(compartments); - pickItems.put(tenancy.getName() + " (root)", tenancy); // NOI18N - return pickItems; - } - - private static Map computeFlatNames(Map compartments) { - Map pickItems = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - for (FlatCompartmentItem comp : compartments.values()) { - pickItems.put(comp.getName(), comp); - } - return pickItems; - } - - private static abstract class FlatCompartmentItem extends CompartmentItem { - - private final OCID parentId; - private String flatName; - - private FlatCompartmentItem(Compartment ociComp) { - super(OCID.of(ociComp.getId(), "Compartment"), ociComp.getCompartmentId(), ociComp.getName()); // NOI18N - setDescription(ociComp.getDescription()); - parentId = OCID.of(ociComp.getCompartmentId(), "Compartment"); // NOI18N - } - - public String getName() { - if (parentId.getValue() == null) { - return ""; - } - if (flatName == null) { - String parentFlatName = ""; - FlatCompartmentItem parentComp = getItem(parentId); - if (parentComp != null) { - parentFlatName = parentComp.getName(); - } - flatName = super.getName(); - if (!parentFlatName.isEmpty()) { - flatName = parentFlatName + "/" + flatName; // NOI18N - } - } - return flatName; - } - - abstract FlatCompartmentItem getItem(OCID compId); - } - protected static Map getDevopsProjects(String compartmentId) { try (DevopsClient client = new DevopsClient(OCIManager.getDefault().getConfigProvider());) { ListProjectsRequest request = ListProjectsRequest.builder().compartmentId(compartmentId).build(); diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddNewAssetCommand.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddNewAssetCommand.java index 9ce97faa9ff1..c98adcfce38a 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddNewAssetCommand.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddNewAssetCommand.java @@ -18,7 +18,6 @@ */ package org.netbeans.modules.cloud.oracle.assets; -import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -28,24 +27,12 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import org.netbeans.api.project.Project; -import org.netbeans.api.project.ProjectUtils; import org.netbeans.modules.cloud.oracle.assets.Steps.ItemTypeStep; -import org.netbeans.modules.cloud.oracle.assets.Steps.ProjectStep; -import org.netbeans.modules.cloud.oracle.assets.Steps.SuggestedContext; import org.netbeans.modules.cloud.oracle.items.OCIItem; -import org.netbeans.modules.project.dependency.ArtifactSpec; -import org.netbeans.modules.project.dependency.Dependency; -import org.netbeans.modules.project.dependency.DependencyChange; -import org.netbeans.modules.project.dependency.DependencyChangeException; -import org.netbeans.modules.project.dependency.ProjectDependencies; -import org.netbeans.modules.project.dependency.ProjectOperationException; -import org.netbeans.modules.refactoring.spi.ModificationResult; -import org.netbeans.modules.project.dependency.Scope; import org.netbeans.spi.lsp.CommandProvider; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.Pair; -import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ServiceProvider; /** @@ -81,69 +68,21 @@ public Set getCommands() { @Override public CompletableFuture runCommand(String command, List arguments) { CompletableFuture future = new CompletableFuture(); - NewSuggestedContext context = new NewSuggestedContext(OpenProjectsFinder.getDefault().findTopLevelProjects()); - Lookup lookup = Lookups.fixed(context); Steps.getDefault() - .executeMultistep(new ItemTypeStep(), lookup) + .executeMultistep(new ItemTypeStep(), Lookup.EMPTY) .thenAccept(result -> { Project project = ((Pair) result).first(); OCIItem item = ((Pair) result).second(); CloudAssets.getDefault().addItem(item); - Project projectToModify = null; - Set subProjects = ProjectUtils.getContainedProjects(project, false); - for (Project subProject : subProjects) { - if ("oci".equals(subProject.getProjectDirectory().getName())) { //NOI18N - projectToModify = subProject; - break; - } - } - if (projectToModify == null) { - projectToModify = project; - } - if (projectToModify != null) { - String[] art = DEP_MAP.get(context.getItemType()); - ArtifactSpec spec = ArtifactSpec.make(art[0], art[1]); - Dependency dep = Dependency.make(spec, Scope.named("implementation")); //NOI18N - DependencyChange change = DependencyChange.add(Collections.singletonList(dep), DependencyChange.Options.skipConflicts); - try { - ModificationResult mod = ProjectDependencies.modifyDependencies(projectToModify, change); - mod.commit(); - } catch (IOException ex) { - future.completeExceptionally(ex); - } catch (DependencyChangeException ex) { - future.completeExceptionally(ex); - } catch (ProjectOperationException ex) { - future.completeExceptionally(ex); - } + String[] art = DEP_MAP.get(item.getKey().getPath()); + try { + DependencyUtils.addDependency(project, art[0], art[1]); + } catch (IllegalStateException e) { + future.completeExceptionally(e); } }); future.complete(null); return future; } - private final class NewSuggestedContext implements SuggestedContext { - - private final CompletableFuture projects; - private String itemType = null; - - public NewSuggestedContext(CompletableFuture projects) { - this.projects = projects; - } - - @Override - public String getItemType() { - return itemType; - } - - @Override - public Step getNextStep() { - return new ProjectStep(projects); - } - - @Override - public void setItemType(String itemType) { - this.itemType = itemType; - } - } - } diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddSuggestedItemAction.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddSuggestedItemAction.java index 49aa0e1e3662..6e6a7815fb1e 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddSuggestedItemAction.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/AddSuggestedItemAction.java @@ -22,7 +22,6 @@ import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.CompletableFuture; import java.util.logging.Logger; import org.netbeans.api.db.explorer.ConnectionManager; import org.netbeans.api.db.explorer.DatabaseConnection; @@ -87,8 +86,8 @@ public void actionPerformed(ActionEvent e) { String ocid = connections[i].getConnectionProperties().getProperty("OCID"); //NOI18N String compartmentId = connections[i].getConnectionProperties().getProperty("CompartmentOCID"); //NOI18N if (ocid != null && compartmentId != null) { - DatabaseItem dbItem = - new DatabaseItem(OCID.of(ocid, "Databases"), compartmentId, name, null, name); //NOI18N + DatabaseItem dbItem + = new DatabaseItem(OCID.of(ocid, "Databases"), compartmentId, name, null, name); //NOI18N adbConnections.put(name, dbItem); } } @@ -103,34 +102,12 @@ public void actionPerformed(ActionEvent e) { } return; } - Lookup lookup = Lookups.fixed(new SingleSuggestedContext(context.getPath())); + Steps.NextStepProvider nsProvider = Steps.NextStepProvider.builder() + .stepForClass(Steps.CompartmentStep.class, (s) -> new Steps.SuggestedStep(context.getPath())) + .build(); + Lookup lookup = Lookups.fixed(nsProvider); Steps.getDefault().executeMultistep(new TenancyStep(), lookup) .thenAccept(result -> CloudAssets.getDefault().addItem((OCIItem) result)); } - - private final class SingleSuggestedContext implements Steps.SuggestedContext { - - private String itemType = null; - - public SingleSuggestedContext(String itemType) { - this.itemType = itemType; - } - - @Override - public String getItemType() { - return itemType; - } - - @Override - public Step getNextStep() { - return null; - } - - @Override - public void setItemType(String itemType) { - this.itemType = itemType; - } - - } } diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java index 1ec06eafb4fe..b9cf8b17c670 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java @@ -38,10 +38,13 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import javax.swing.event.ChangeListener; import org.netbeans.api.db.explorer.ConnectionManager; import org.netbeans.api.db.explorer.DatabaseConnection; +import org.netbeans.modules.cloud.oracle.OCIChildFactory; import org.netbeans.modules.cloud.oracle.bucket.BucketItem; import org.netbeans.modules.cloud.oracle.compute.ClusterItem; import org.netbeans.modules.cloud.oracle.compute.ComputeInstanceItem; @@ -54,12 +57,14 @@ import org.openide.filesystems.FileUtil; import org.openide.util.ChangeSupport; import org.openide.util.Exceptions; +import org.openide.util.Parameters; /** * * @author Jan Horvath */ public final class CloudAssets { + private static final Logger LOG = Logger.getLogger(CloudAssets.class.getName()); private static final String SUGGESTED = "Suggested"; //NOI18N private static final String CLOUD_ASSETS_PATH = "CloudAssets"; //NOI18N @@ -111,6 +116,7 @@ public static synchronized CloudAssets getDefault() { } public void addItem(OCIItem newItem) { + Parameters.notNull("newItem cannot be null", newItem); items.add(newItem); update(); storeAssets(); @@ -132,11 +138,6 @@ public void update() { } private synchronized void setSuggestions(Set newSuggested) { -// for (OCIItem item : new HashSet(items)) { -// if (item.getKey().getPath().equals(SUGGESTED)) { //NOI18N -// items.remove(item); -// } -// } suggested.clear(); Set present = items.stream() .map(i -> i.getKey().getPath()) @@ -147,7 +148,7 @@ private synchronized void setSuggestions(Set newSuggested) { for (String exclusivePath : s.getExclusivePaths()) { if (present.contains(exclusivePath)) { add = false; - continue; + break; } } if (add) { @@ -161,15 +162,6 @@ private synchronized void setSuggestions(Set newSuggested) { public List getItems() { List list = new ArrayList<>(suggested); list.addAll(items); -// Collections.sort(list, (a, b) -> { -// if (SUGGESTED.equals(a.getKey().getPath())) { -// return Integer.MIN_VALUE; -// } -// if (SUGGESTED.equals(b.getKey().getPath())) { -// return Integer.MAX_VALUE; -// } -// return a.getKey().getPath().compareTo(b.getKey().getPath()); -// }); return list; } @@ -229,7 +221,7 @@ synchronized void loadAssets() { } content = new String(file.asBytes()); } catch (IOException ex) { - Exceptions.printStackTrace(ex); + LOG.log(Level.INFO, "Unable to load assets", ex); return; } finally { assetsLoaded = true; @@ -264,7 +256,7 @@ synchronized void loadAssets() { reader.endArray(); items = loaded; } catch (JsonIOException | JsonSyntaxException | IOException e) { - Exceptions.printStackTrace(e); + LOG.log(Level.INFO, "Unable to load assets", e); } finally { assetsLoaded = true; } diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependencyUtils.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependencyUtils.java new file mode 100644 index 000000000000..5d5548045ba8 --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/DependencyUtils.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.modules.cloud.oracle.assets; + +import java.io.IOException; +import java.util.Collections; +import java.util.Set; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.modules.project.dependency.ArtifactSpec; +import org.netbeans.modules.project.dependency.Dependency; +import org.netbeans.modules.project.dependency.DependencyChange; +import org.netbeans.modules.project.dependency.DependencyChangeException; +import org.netbeans.modules.project.dependency.ProjectDependencies; +import org.netbeans.modules.project.dependency.ProjectOperationException; +import org.netbeans.modules.project.dependency.Scopes; +import org.netbeans.modules.refactoring.spi.ModificationResult; + +/** + * Utility class with methods for modifying project dependencies. + * + * @author Jan Horvath + */ +public class DependencyUtils { + + public static void addDependency(Project project, String groupId, String artifactId) { + Project projectToModify = null; + Set subProjects = ProjectUtils.getContainedProjects(project, false); + for (Project subProject : subProjects) { + if ("oci".equals(subProject.getProjectDirectory().getName())) { //NOI18N + projectToModify = subProject; + break; + } + } + if (projectToModify == null) { + projectToModify = project; + } + if (projectToModify != null) { + ArtifactSpec spec = ArtifactSpec.make(groupId, artifactId); + Dependency dep = Dependency.make(spec, Scopes.COMPILE); + DependencyChange change = DependencyChange.add(Collections.singletonList(dep), DependencyChange.Options.skipConflicts); + try { + ModificationResult mod = ProjectDependencies.modifyDependencies(projectToModify, change); + mod.commit(); + } catch (IOException | DependencyChangeException | ProjectOperationException ex) { + throw new IllegalStateException(ex); + } + } + } + +} diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Step.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Step.java index 83d151e275ff..3bb8721dd13c 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Step.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Step.java @@ -25,7 +25,7 @@ * * @author Jan Horvath */ -interface Step { +public interface Step { Step prepare(T item, Lookup lookup); diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Steps.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Steps.java index 36129eef0c02..fe3f4c19fa2c 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Steps.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Steps.java @@ -37,9 +37,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectInformation; @@ -65,9 +65,12 @@ import org.openide.util.NbBundle; import org.openide.util.Pair; import org.openide.util.RequestProcessor; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ProxyLookup; /** - * + * An implementation of the {@link Step} interface used for multiple commands or actions. + * * @author Jan Horvath */ @NbBundle.Messages({ @@ -98,11 +101,83 @@ public CompletableFuture executeMultistep(Step firstStep, Lookup lookup) if (DialogDescriptor.OK_OPTION == dd.notify(ci)) { future.complete(multistep.getResult()); } else { - future.complete(null); + future.cancel(true); } }); return future; } + + /** + * Provider class that supplies the next {@link Step} for navigation from the current {@link Step}. + * + */ + public static class NextStepProvider { + private final Map, Function> steps; + + /** + * Private constructor to initialize the NextStepProvider with a map of steps. + * + * @param steps a map associating classes with their corresponding {@link Step} instances + */ + private NextStepProvider(Map, Function> steps) { + this.steps = steps; + } + + /** + * Retrieves the next {@link Step} for the specified {@link Step}. + * + * @param currentStep the current step for which the next step is to be retrieved + * @return the {@link Step} associated with the specified class, or null if no step is found + */ + public Step nextStepFor(Step currentStep) { + Function nextStep = steps.get(currentStep.getClass()); + return nextStep != null ? nextStep.apply(currentStep) : null; + } + + /** + * Creates a new Builder for constructing a NextStepProvider. + * + * @return a new Builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder class for constructing a NextStepProvider. + */ + public static class Builder { + private final Map, Function> steps = new HashMap<> (); + + /** + * Private constructor for the Builder. + */ + private Builder() { + } + + /** + * Associates a {@link Step} function with a class in the builder. + * + * @param clazz the class to be associated with the step function + * @param stepFunction the function to be associated with the class + * @return the current Builder instance for method chaining + */ + public Builder stepForClass(Class clazz, Function stepFunction) { + steps.put(clazz, stepFunction); + return this; + } + + /** + * Builds and returns a NextStepProvider with the configured steps. + * + * @return a new NextStepProvider instance + */ + public NextStepProvider build() { + return new NextStepProvider(steps); + } + } + } + private static class Multistep { @@ -172,8 +247,7 @@ public Object getResult() { } } - static final class TenancyStep implements Step { - + public static final class TenancyStep implements Step { List profiles = new LinkedList<>(); private AtomicReference selected = new AtomicReference<>(); private Lookup lookup; @@ -243,9 +317,8 @@ public boolean onlyOneChoice() { return profiles.stream().filter(p -> p.getTenancy().isPresent()).count() == 1; } } - - static final class CompartmentStep implements Step { - + + public static final class CompartmentStep implements Step { private Map compartments = null; private CompartmentItem selected; private Lookup lookup; @@ -276,7 +349,14 @@ public NotifyDescriptor createInput() { @Override public Step getNext() { - return new SuggestedStep().prepare(getValue(), lookup); + NextStepProvider nsProvider = lookup.lookup(NextStepProvider.class); + if (nsProvider != null) { + Step ns = nsProvider.nextStepFor(this); + if (ns != null) { + return ns.prepare(getValue(), lookup); + } + } + return null; } @Override @@ -298,18 +378,6 @@ public boolean onlyOneChoice() { } } - /** - * Context of SuggestedStep. Determines next step. - */ - public interface SuggestedContext { - - String getItemType(); - - Step getNextStep(); - - public void setItemType(String selected); - } - /** * Show list of items for a suggested type. * @@ -319,16 +387,19 @@ static class SuggestedStep implements Step { private Map items = new HashMap<>(); private OCIItem selected; private Lookup lookup; - private SuggestedContext context = null; + private final String suggestedType; + public SuggestedStep(String suggestedType) { + this.suggestedType = suggestedType; + } + public SuggestedStep prepare(CompartmentItem compartment, Lookup lookup) { this.lookup = lookup; - context = lookup.lookup(SuggestedContext.class); ProgressHandle h = ProgressHandle.createHandle(Bundle.CollectingItems()); h.start(); h.progress(Bundle.CollectingItems_Text()); try { - getItemsByPath(compartment, context.getItemType()).forEach((db) -> items.put(db.getName(), db)); + getItemsByPath(compartment, suggestedType).forEach((db) -> items.put(db.getName(), db)); } finally { h.finish(); } @@ -336,7 +407,7 @@ public SuggestedStep prepare(CompartmentItem compartment, Lookup lookup) { } private String getSuggestedItemName() { - switch (context.getItemType()) { + switch (suggestedType) { case "Databases": return Bundle.Databases(); case "Vault": @@ -348,7 +419,7 @@ private String getSuggestedItemName() { case "ComputeInstance": return Bundle.Compute(); } - throw new MissingResourceException("Missing OCI type", null, context.getItemType()); + throw new MissingResourceException("Missing OCI type", null, suggestedType); } @Override @@ -358,11 +429,14 @@ public NotifyDescriptor createInput() { @Override public Step getNext() { - Step next = context.getNextStep(); - if (next != null) { - next.prepare(getValue(), lookup); - } - return next; + NextStepProvider nsProvider = lookup.lookup(NextStepProvider.class); + if (nsProvider != null) { + Step ns = nsProvider.nextStepFor(this); + if (ns != null) { + return ns.prepare(getValue(), lookup); + } + } + return null; } @Override @@ -395,8 +469,6 @@ private static NotifyDescriptor.QuickPick createQuickPick(Ma } return new NotifyDescriptor.QuickPick(title, title, items, false); } - - /** * Retrieve all compartments from a tenancy. @@ -487,11 +559,10 @@ static class ItemTypeStep implements Step { String[] types = {"Databases", "Vault", "Bucket"}; //NOI18N private Lookup lookup; - private SuggestedContext context; + private String selected; @Override public Step prepare(Object item, Lookup lookup) { - context = lookup.lookup(SuggestedContext.class); this.lookup = lookup; return this; } @@ -512,17 +583,21 @@ public boolean onlyOneChoice() { @Override public Step getNext() { - return new TenancyStep().prepare(null, lookup); + NextStepProvider nsProvider = NextStepProvider.builder() + .stepForClass(CompartmentStep.class, (s) -> new SuggestedStep(getValue())) + .stepForClass(SuggestedStep.class, (s) -> new ProjectStep()) + .build(); + return new TenancyStep().prepare(null, new ProxyLookup(Lookups.fixed(nsProvider), lookup)); } @Override public void setValue(String selected) { - context.setItemType(selected); + this.selected = selected; } @Override public String getValue() { - return context.getItemType(); + return selected; } } @@ -530,20 +605,20 @@ public String getValue() { /** * The purpose of this step is to select a project to update dependencies. */ - static class ProjectStep implements Step { + public static class ProjectStep implements Step { private final CompletableFuture projectsFuture; Map projects; private Project selectedProject; - private OCIItem item; + private Object item; - ProjectStep(CompletableFuture projectsFuture) { - this.projectsFuture = projectsFuture; + public ProjectStep() { + projectsFuture = OpenProjectsFinder.getDefault().findTopLevelProjects(); this.projects = new HashMap<> (); } @Override - public Step prepare(OCIItem item, Lookup lookup) { + public Step prepare(Object item, Lookup lookup) { this.item = item; try { Project[] p = projectsFuture.get();