| /******************************************************************************* |
| * Copyright (c) 2010, 2014 Itema AS and others. |
| * 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 |
| * |
| * Contributors: |
| * Torkild U. Resheim - initial API and implementation |
| * Torkild U. Resheim - Uniquely identify Jenkins servers, bug 341725 |
| * Torkild U. Resheim - Distinguish between Hudson and Jenkins, bug 353861 |
| * Tasktop Technologies - improvements |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.internal.hudson.ui; |
| |
| import java.net.URISyntaxException; |
| import java.util.List; |
| import java.util.UUID; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.ecf.core.ContainerConnectException; |
| import org.eclipse.ecf.core.ContainerCreateException; |
| import org.eclipse.ecf.core.ContainerFactory; |
| import org.eclipse.ecf.core.IContainer; |
| import org.eclipse.ecf.discovery.IDiscoveryLocator; |
| import org.eclipse.ecf.discovery.IServiceEvent; |
| import org.eclipse.ecf.discovery.IServiceInfo; |
| import org.eclipse.ecf.discovery.IServiceListener; |
| import org.eclipse.ecf.discovery.IServiceProperties; |
| import org.eclipse.ecf.discovery.identity.IServiceID; |
| import org.eclipse.ecf.discovery.identity.IServiceTypeID; |
| import org.eclipse.mylyn.builds.ui.BuildsUi; |
| import org.eclipse.mylyn.commons.core.StatusHandler; |
| import org.eclipse.mylyn.commons.repositories.core.RepositoryLocation; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * This class implements a mechanism for discovering Hudson and Jenkins servers through the use of Multicast DNS (MDNS). |
| * |
| * @author Torkild U. Resheim, Itema AS |
| * @author Steffen Pingel |
| */ |
| public class HudsonDiscovery { |
| /** |
| * This class works around a source incompatibility between the org.eclipse.ecf.discovery version in Luna and |
| * earlier versions. Version 5.0 added the triggerDiscovery method to IServiceListener. This class can be extended |
| * in order to implement this method without the @Overide annotation causing compilation to fail against earlier |
| * versions (e.g. Kepler). |
| */ |
| private static abstract class AbstractServiceListener { |
| public abstract boolean triggerDiscovery(); |
| } |
| |
| private final class HudsonServiceListener extends AbstractServiceListener implements IServiceListener { |
| public void serviceDiscovered(IServiceEvent anEvent) { |
| IServiceInfo serviceInfo = anEvent.getServiceInfo(); |
| IServiceID serviceId = serviceInfo.getServiceID(); |
| IServiceTypeID serviceTypeId = serviceId.getServiceTypeID(); |
| // Note that Jenkins will claim that it's both Jenkins and |
| // Hudson for backward compatibility. |
| if (serviceTypeId.getName().equals(JENKINS_MDNS_ID)) { |
| IServiceProperties properties = serviceInfo.getServiceProperties(); |
| try { |
| if (properties.getProperty(URL_PROPERTY) == null) { |
| notifyMessage(Messages.JenkinsDiscovery_MessageTitle, NLS.bind( |
| Messages.JenkinsDiscovery_MissingURL, new Object[] { serviceInfo.getLocation() |
| .getHost() })); |
| } else { |
| issueJenkinsNotification(properties); |
| } |
| } catch (URISyntaxException e) { |
| StatusHandler.log(new Status(IStatus.ERROR, HudsonConnectorUi.ID_PLUGIN, NLS.bind( |
| Messages.Discovery_IncorrectURI, new Object[] { properties.getProperty(URL_PROPERTY) |
| .toString() }), e)); |
| } |
| } |
| if (serviceTypeId.getName().equals(HUDSON_MDNS_ID)) { |
| IServiceProperties properties = serviceInfo.getServiceProperties(); |
| try { |
| if (properties.getProperty(URL_PROPERTY) == null) { |
| notifyMessage(Messages.HudsonDiscovery_MessageTitle, NLS.bind( |
| Messages.HudsonDiscovery_MissingURL, |
| new Object[] { serviceInfo.getLocation().getHost() })); |
| } else { |
| issueHudsonNotification(properties); |
| } |
| } catch (URISyntaxException e) { |
| StatusHandler.log(new Status(IStatus.ERROR, HudsonConnectorUi.ID_PLUGIN, NLS.bind( |
| Messages.Discovery_IncorrectURI, new Object[] { properties.getProperty(URL_PROPERTY) |
| .toString() }), e)); |
| } |
| } |
| } |
| |
| public void serviceUndiscovered(IServiceEvent anEvent) { |
| // Ignore this for now |
| } |
| |
| @Override |
| public boolean triggerDiscovery() { |
| return false; |
| } |
| } |
| |
| private static final String ECF_DISCOVERY_JMDNS = "ecf.discovery.jmdns"; //$NON-NLS-1$ |
| |
| private static final String HUDSON_MDNS_ID = "_hudson._tcp.local._iana"; //$NON-NLS-1$ |
| |
| private static final String JENKINS_MDNS_ID = "_jenkins._tcp.local._iana"; //$NON-NLS-1$ |
| |
| private static final String URL_PROPERTY = "url"; //$NON-NLS-1$ |
| |
| /** Server id property name (Jenkins only). */ |
| private static final String SERVER_ID_PROPERTY = "server-id"; //$NON-NLS-1$ |
| |
| private IContainer container; |
| |
| public HudsonDiscovery() { |
| } |
| |
| protected IContainer getContainer() throws ContainerCreateException { |
| return ContainerFactory.getDefault().createContainer(ECF_DISCOVERY_JMDNS); |
| } |
| |
| /** |
| * Determines whether or not the detected server is a new server or not. |
| * |
| * @param url |
| * the server URL |
| * @param id |
| * the server identifier |
| * @return <code>true</code> if the detected server is new. |
| */ |
| private boolean isNew(String url, String id) { |
| if (url == null) { |
| return false; |
| } |
| List<RepositoryLocation> locations = BuildsUi.getServerLocations(); |
| for (RepositoryLocation location : locations) { |
| if (location.hasUrl(url) || location.getId().equals(id)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public void start() { |
| try { |
| container = getContainer(); |
| final IDiscoveryLocator adapter = (IDiscoveryLocator) container.getAdapter(IDiscoveryLocator.class); |
| adapter.addServiceListener(new HudsonServiceListener()); |
| container.connect(null, null); |
| |
| } catch (ContainerCreateException e) { |
| StatusHandler.log(new Status(IStatus.WARNING, HudsonConnectorUi.ID_PLUGIN, |
| Messages.Discovery_CouldNotStartService, e)); |
| } catch (ContainerConnectException e) { |
| StatusHandler.log(new Status(IStatus.WARNING, HudsonConnectorUi.ID_PLUGIN, |
| Messages.Discovery_CouldNotStartService, e)); |
| } |
| } |
| |
| public void stop() { |
| if (container != null) { |
| container.disconnect(); |
| container = null; |
| } |
| } |
| |
| private void notifyMessage(String title, String description) { |
| BuildsUi.serverDiscovered(title, description); |
| } |
| |
| private void issueHudsonNotification(IServiceProperties properties) throws URISyntaxException { |
| String url = properties.getProperty(URL_PROPERTY).toString(); |
| String id = getId(properties); |
| if (isNew(url, id)) { |
| notifyMessage( |
| Messages.HudsonDiscovery_MessageTitle, |
| NLS.bind(Messages.HudsonDiscovery_MessageText, new Object[] { url, |
| Messages.HudsonDiscovery_ServerName, url, id })); |
| } |
| } |
| |
| private void issueJenkinsNotification(IServiceProperties properties) throws URISyntaxException { |
| String url = properties.getProperty(URL_PROPERTY).toString(); |
| String id = getId(properties); |
| if (isNew(url, id)) { |
| // Change the first segment (org.eclipse.mylyn.hudson) to the id of |
| // the new repository type when we start differentiation between the two |
| notifyMessage( |
| Messages.JenkinsDiscovery_MessageTitle, |
| NLS.bind(Messages.JenkinsDiscovery_MessageText, new Object[] { url, |
| Messages.JenkinsDiscovery_ServerName, url, id })); |
| } |
| } |
| |
| private String getId(IServiceProperties properties) { |
| String id = (String) properties.getProperty(SERVER_ID_PROPERTY); |
| if (id == null) { |
| id = UUID.randomUUID().toString(); |
| } |
| return id; |
| } |
| |
| } |