/** * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * All rights reserved. This program and the accompanying materials are 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. * */ package gov.redhawk.ui.views.namebrowser.view; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.fieldassist.ComboContentAdapter; import org.eclipse.jface.fieldassist.ContentProposal; import org.eclipse.jface.fieldassist.ContentProposalAdapter; import org.eclipse.jface.fieldassist.IContentProposal; import org.eclipse.jface.fieldassist.IContentProposalProvider; import org.eclipse.jface.viewers.DecoratingLabelProvider; import org.eclipse.jface.viewers.ILabelDecorator; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.WorkbenchJob; import org.omg.CORBA.SystemException; import org.omg.CORBA.UserException; import org.omg.CosNaming.Binding; import org.omg.CosNaming.BindingIteratorHolder; import org.omg.CosNaming.BindingListHolder; import org.omg.CosNaming.BindingType; import org.omg.CosNaming.NamingContextExt; import org.omg.CosNaming.NamingContextExtHelper; import CF.DomainManagerHelper; import gov.redhawk.sca.ui.compatibility.CompatibilityFactory; import gov.redhawk.sca.util.Debug; import gov.redhawk.ui.views.namebrowser.NameBrowserPlugin; import gov.redhawk.ui.views.namebrowser.view.internal.BindingContentProvider; /** * @since 1.1 */ public class NameBrowserView extends ViewPart { /** The ID of this view */ public static final String ID = "gov.redhawk.ui.views.namebrowserview"; /** The ID of this view */ public static final String HIST_MEMENTO_ID = NameBrowserView.ID + ".history"; /** The main object of the view, the tree of applications */ private TreeViewer treeViewer; /** The TreeViewers content provider */ private BindingContentProvider contentProvider = null; /** The list of connected NameServers (also the tree root) */ private final List<BindingNode> connectedHosts = new ArrayList<BindingNode>(); /** The list of connected NameServers (also the tree root) */ private Set<String> nameServerHistory = new HashSet<String>(); private static final Debug DEBUG = new Debug(NameBrowserPlugin.PLUGIN_ID, "contentprovider"); private Combo nameServerField; private Button connectButton; private final IContentProposalProvider proposalProvider = new IContentProposalProvider() { @Override public IContentProposal[] getProposals(final String contents, final int position) { final List<IContentProposal> list = new ArrayList<IContentProposal>(); final String regexp = ".*" + contents.replace("*", ".*") + ".*"; final Pattern pattern = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE); for (final String proposal : NameBrowserView.this.nameServerHistory) { final Matcher matcher = pattern.matcher(proposal); if (proposal.length() >= contents.length() && matcher.matches()) { list.add(new ContentProposal(proposal)); } } return list.toArray(new IContentProposal[list.size()]); } }; @Override public void createPartControl(final Composite parent) { final GridLayout gridLayout = new GridLayout(3, false); parent.setLayout(gridLayout); final Label nameServerLabel = new Label(parent, SWT.NONE); nameServerLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false, 1, 1)); nameServerLabel.setText("Name Server:"); this.nameServerField = new Combo(parent, SWT.BORDER); final ComboContentAdapter controlAdapter = new ComboContentAdapter(); final ContentProposalAdapter contentProposalAdapter = CompatibilityFactory.createContentProposalAdapter(this.nameServerField, controlAdapter, this.proposalProvider, null); contentProposalAdapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE); this.nameServerField.setToolTipText("The CORBA URI of the NameServer"); this.nameServerField.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 1, 1)); this.nameServerField.setText(""); // disable connect button when name server text empty nameServerField.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { final String newRef = NameBrowserView.this.nameServerField.getText().trim(); connectButton.setEnabled(!newRef.isEmpty()); } }); // this listener doesn't seem to do anything. this.nameServerField.addSelectionListener(new SelectionAdapter() { @Override public void widgetDefaultSelected(final SelectionEvent e) { final String newRef = NameBrowserView.this.nameServerField.getText().trim(); if ("".equals(newRef)) { return; } addConnection(newRef); } }); connectButton = new Button(parent, SWT.PUSH); connectButton.setImage(NameBrowserPlugin.getDefault().getImageRegistry().get(NameBrowserPlugin.CONNECT)); connectButton.setToolTipText("Connect to the specified host"); connectButton.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false, 1, 1)); connectButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final String newRef = NameBrowserView.this.nameServerField.getText().trim(); addConnection(newRef); } }); this.treeViewer = new TreeViewer(parent, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.VIRTUAL); this.treeViewer.getControl().setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 3, 1)); getSite().setSelectionProvider(this.treeViewer); this.contentProvider = new BindingContentProvider(); this.treeViewer.setContentProvider(this.contentProvider); ILabelDecorator decorator = PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(); this.treeViewer.setLabelProvider(new DecoratingLabelProvider(new WorkbenchLabelProvider(), decorator)); this.treeViewer.setComparator(new ViewerComparator() { @Override public int compare(final Viewer viewer, final Object e1, final Object e2) { if (e1 instanceof BindingNode && e2 instanceof BindingNode) { final BindingNode b1 = (BindingNode) e1; final BindingNode b2 = (BindingNode) e2; if (b1.getType() != b2.getType()) { switch (b1.getType()) { case CONTEXT: return -1; case OBJECT: switch (b2.getType()) { case CONTEXT: return 1; default: break; } break; case ROOT: return -1; default: break; } } } return super.compare(viewer, e1, e2); } }); this.treeViewer.setInput(this.connectedHosts); // Setup right click menu final MenuManager manager = new MenuManager(); final Menu menu = manager.createContextMenu(this.treeViewer.getTree()); this.treeViewer.getTree().setMenu(menu); getSite().registerContextMenu(NameBrowserView.ID, manager, this.treeViewer); for (final String nameServer : this.nameServerHistory) { this.nameServerField.add(nameServer); } NameBrowserPlugin.getDefault().setSessionDisplay(getSite().getShell().getDisplay()); } @Override public void setFocus() { this.treeViewer.getControl().setFocus(); } /** * This method connects to the selected Host to retrieve the name listing * * @param newRef the corba ref of the host to connect to * @param monitor the monitor for job tracking * @param refresh true to refresh the tree after connecting */ private void connect(final String newRef) { // Create the job to connect and get the name list final Job connectJob = new Job("Connect to Name Server") { @Override protected IStatus run(final IProgressMonitor monitor) { final BindingNode newRootNode = new BindingNode(newRef); try { newRootNode.connect(); } catch (final Exception e) { // SUPPRESS CHECKSTYLE Logged Catch all exception newRootNode.dispose(); return new Status(IStatus.ERROR, NameBrowserPlugin.PLUGIN_ID, "Error connecting to the name server, see Error Log for details.", e); } NameBrowserView.this.connectedHosts.add(newRootNode); final WorkbenchJob job = new WorkbenchJob(getSite().getShell().getDisplay(), "Adding Corba Name Service") { @Override public IStatus runInUIThread(final IProgressMonitor monitor) { NameBrowserView.this.treeViewer.refresh(NameBrowserView.this.connectedHosts); return Status.OK_STATUS; } }; job.schedule(); return Status.OK_STATUS; } }; connectJob.setUser(true); connectJob.setPriority(Job.LONG); connectJob.schedule(10); // SUPPRESS CHECKSTYLE MagicNumber } /** * This method disconnects from the specified NameServer * * @param host the NameServer to disconnect from */ public void disconnect(final BindingNode node) { node.dispose(); this.connectedHosts.remove(node.getRoot()); final WorkbenchJob job = new WorkbenchJob(getSite().getShell().getDisplay(), "Destroy Orb Job") { @Override public IStatus runInUIThread(final IProgressMonitor monitor) { NameBrowserView.this.treeViewer.remove(node.getRoot()); return Status.OK_STATUS; } }; job.schedule(); } @Override public void init(final IViewSite site, final IMemento memento) throws PartInitException { super.init(site, memento); if (memento != null) { final String nameHistoryString = memento.getString(NameBrowserView.HIST_MEMENTO_ID); if (nameHistoryString != null) { final String[] values = nameHistoryString.split(","); this.nameServerHistory = new HashSet<String>(Arrays.asList(values)); } } } @Override public void init(final IViewSite site) throws PartInitException { this.nameServerHistory = new HashSet<String>(); super.init(site); } @Override public void saveState(final IMemento memento) { final StringBuffer sb = new StringBuffer(); for (final String nameServer : this.nameServerHistory) { sb.append(nameServer); sb.append(','); } memento.putString(NameBrowserView.HIST_MEMENTO_ID, sb.toString()); super.saveState(memento); } private void addConnection(final String initRef) { String newRef = this.nameServerField.getText().trim(); if (!(newRef.startsWith("IOR:") || newRef.startsWith("corbaloc::") || newRef.startsWith("corbaname::"))) { newRef = "corbaname::" + newRef; } // No need to reconnect to the same thing for (final BindingNode node : this.connectedHosts) { if (node.getHost().equals(newRef)) { return; } } // Local-host can be connected to by multiple strings. // Check to make sure duplicate connections are not made to local-host. List<String> localhostVariants = new ArrayList<String>(Arrays.asList("corbaname::", "corbaname::localhost", "corbaname::127.0.0.1")); for (String localhostVariant : localhostVariants) { if (localhostVariant.equals(newRef)) { for (final BindingNode node : this.connectedHosts) { if (localhostVariants.contains(node.getHost())) { return; } } // Set all local-host connections to the same string newRef = "corbaname::127.0.0.1"; } } connect(newRef); this.nameServerHistory.add(newRef); final List<String> tmpList = new ArrayList<String>(this.nameServerHistory); Collections.sort(tmpList); this.nameServerField.setItems(tmpList.toArray(new String[tmpList.size()])); } /** * This will refresh the displayed NameService(s). * * @param node the node to refresh, or null for all of them */ public void refresh(final BindingNode... nodes) { if (nodes == null || nodes.length == 0) { for (final BindingNode node : this.connectedHosts) { node.clearContents(); } this.treeViewer.refresh(); } else { for (final BindingNode node : nodes) { node.clearContents(); this.treeViewer.refresh(node); } } } /** * This will a naming object from the NameService. This does nothing for naming contexts. * * @param node the node to unbind */ public void unbind(final List<BindingNode> unbindingList) { final Set<BindingNode> nodes = new HashSet<BindingNode>(); for (final BindingNode node : unbindingList) { // You can remove only a context, doesn't work for an object if (node.getType() == BindingNode.Type.OBJECT) { final NamingContextExt rootContext = node.getNamingContext(); try { // Unbind the name rootContext.unbind(rootContext.to_name(node.getPath())); } catch (final UserException e) { if (NameBrowserView.DEBUG.enabled) { DEBUG.message("UserException occurred: " + e.getMessage()); } } catch (final SystemException e) { if (NameBrowserView.DEBUG.enabled) { DEBUG.message("SystemException occurred: " + e.getMessage()); } } nodes.add(node.getParent()); } } final WorkbenchJob job = new WorkbenchJob(getSite().getShell().getDisplay(), "Unbind Refresh") { @Override public IStatus runInUIThread(final IProgressMonitor monitor) { refresh(nodes.toArray(new BindingNode[nodes.size()])); return Status.OK_STATUS; } }; job.schedule(); } /** * This will remove a naming context node from the NameService. This does nothing for naming objects. * * @param node the node to remove */ public void removeContext(final List<BindingNode> removeList) { final Set<BindingNode> nodes = new HashSet<BindingNode>(); for (final BindingNode node : removeList) { try { // Get the path to the node and narrow to the context // You can remove only a context, doesn't work for an object final String path = node.getPath(); if (node.getType() == BindingNode.Type.CONTEXT) { final NamingContextExt rootContext = node.getNamingContext(); final org.omg.CORBA.Object obj = rootContext.resolve_str(path); final NamingContextExt context = NamingContextExtHelper.narrow(obj); // Recursively remove all the children from this node removeChildren(context, path + "/"); // Destroy the context context.destroy(); // Unbind the name rootContext.unbind(rootContext.to_name(path)); // Refresh the list for this host nodes.add(node.getRoot()); } } catch (UserException e) { if (NameBrowserView.DEBUG.enabled) { DEBUG.message("UserException occurred: " + e.getMessage()); } } } final WorkbenchJob job = new WorkbenchJob(getSite().getShell().getDisplay(), "Refresh") { @Override public IStatus runInUIThread(final IProgressMonitor monitor) { refresh(nodes.toArray(new BindingNode[nodes.size()])); return Status.OK_STATUS; } }; job.schedule(); } private void removeChildren(final NamingContextExt context, final String path) { final BindingListHolder bl = new BindingListHolder(); final BindingIteratorHolder bi = new BindingIteratorHolder(); // Get a list of everything in this context try { context.list(-1, bl, bi); } catch (final SystemException e) { if (NameBrowserView.DEBUG.enabled) { DEBUG.message("SystemException occurred: " + e.getMessage()); } } if (bl.value == null) { return; } // Remove everything in this context for (final Binding b : bl.value) { final String newPath = path + b.binding_name[0].id; // Recursively unbind/delete context types // Only need to unbind object types try { if (b.binding_type == BindingType.ncontext) { // Resolve the naming context final org.omg.CORBA.Object obj = context.resolve(b.binding_name); final NamingContextExt c = NamingContextExtHelper.narrow(obj); // Remove all its children removeChildren(c, newPath + "/"); // Destroy the context c.destroy(); } // Unbind the name context.unbind(b.binding_name); } catch (final UserException e) { if (NameBrowserView.DEBUG.enabled) { DEBUG.message("UserException occurred: " + e.getMessage()); } } catch (final SystemException e) { if (NameBrowserView.DEBUG.enabled) { DEBUG.message("SystemException occurred: " + e.getMessage()); } } } } public static boolean isDomainManager(final BindingNode node) { return node.is_a(DomainManagerHelper.id()); } }