Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Coulon2016-11-29 11:32:32 +0000
committerJeff Johnston2016-11-29 21:17:55 +0000
commit1f01289c7cbcf30ef593a0ad06448ed3c4e984ac (patch)
tree556cd72d03463da5361ba34937d28a2494fc5fef
parentf5cd20c288a446f200fcb37e7dfc21826f9d7a06 (diff)
downloadorg.eclipse.linuxtools-1f01289c7cbcf30ef593a0ad06448ed3c4e984ac.tar.gz
org.eclipse.linuxtools-1f01289c7cbcf30ef593a0ad06448ed3c4e984ac.tar.xz
org.eclipse.linuxtools-1f01289c7cbcf30ef593a0ad06448ed3c4e984ac.zip
Bug 508282 - Unable to list image tags on DockerHub
Refactored the code in the AbstractRegistry class to move the logic of retrieving the tags by type of registry in private methods, and implemented the workflow to retrieve a Bearer token if needed when querying on DockerHub. Also, providing the resulting list of tags in a sorted, reverse order. Added a few tests to verify the parsing of the 'Www-Authenticate' response header, and verify that the list of tags for an official image (eg: "php") and a regular image (eg: "jboss/wildfly") can be retrieved. These tests are temporarily ignored because they fail on Hudson (can the salve machine connect to Docker Hub ?) Also: refactored some loops to use the Stream API. Change-Id: I60d7d71188e2e6e3d19a32e6fb1e53cb11605bf8 Signed-off-by: Xavier Coulon <xcoulon@redhat.com> Reviewed-on: https://git.eclipse.org/r/85887 Tested-by: Hudson CI Reviewed-by: Jeff Johnston <jjohnstn@redhat.com>
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/AbstractRegistry.java226
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerImageBuildFailedException.java2
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IRepositoryTag.java1
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.java2
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.properties3
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/OAuth2Utils.java72
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTag.java90
-rw-r--r--containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2.java22
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/docker/core/ImageTagsListTest.java54
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/core/OAuth2UtilsTest.java37
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2Test.java41
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/testutils/MockContainerFactory.java2
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/views/DockerImagesViewSWTBotTest.java3
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EditDockerConnectionSWTBotTest.java6
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DockerImageTagSearchResult.java7
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagPage.java9
-rw-r--r--containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagSelectionPage.java40
17 files changed, 533 insertions, 84 deletions
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/AbstractRegistry.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/AbstractRegistry.java
index d79b393fda..bbb92dbadc 100644
--- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/AbstractRegistry.java
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/AbstractRegistry.java
@@ -14,11 +14,12 @@ import static javax.ws.rs.HttpMethod.GET;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
+import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import javax.ws.rs.client.Client;
@@ -31,8 +32,11 @@ import javax.ws.rs.core.Response.Status;
import org.eclipse.linuxtools.internal.docker.core.DockerImageSearchResult;
import org.eclipse.linuxtools.internal.docker.core.ImageSearchResultV1;
import org.eclipse.linuxtools.internal.docker.core.ImageSearchResultV2;
+import org.eclipse.linuxtools.internal.docker.core.OAuth2Utils;
+import org.eclipse.linuxtools.internal.docker.core.OAuth2Utils.BearerTokenResponse;
import org.eclipse.linuxtools.internal.docker.core.RepositoryTag;
import org.eclipse.linuxtools.internal.docker.core.RepositoryTagV2;
+import org.eclipse.osgi.util.NLS;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.jackson.JacksonFeature;
@@ -49,6 +53,10 @@ public abstract class AbstractRegistry implements IRegistry {
"registry.hub.docker.com", //$NON-NLS-1$
"index.docker.io" //$NON-NLS-1$
};
+
+ private static final ClientConfig DEFAULT_CONFIG = new ClientConfig(
+ ObjectMapperProvider.class, JacksonFeature.class);
+
public static final String DOCKERHUB_REGISTRY = "https://index.docker.io"; //$NON-NLS-1$
// Cache the URL for searches to avoid excessive calls
private String cachedHTTPServerAddress;
@@ -118,9 +126,9 @@ public abstract class AbstractRegistry implements IRegistry {
}
@Override
- public List<IDockerImageSearchResult> getImages(String term) throws DockerException {
- final ClientConfig DEFAULT_CONFIG = new ClientConfig(
- ObjectMapperProvider.class, JacksonFeature.class);
+ public List<IDockerImageSearchResult> getImages(String term)
+ throws DockerException {
+
final Client client = ClientBuilder.newClient(DEFAULT_CONFIG);
List<IDockerImageSearchResult> result = new ArrayList<>();
WebTarget queryImagesResource;
@@ -178,62 +186,170 @@ public abstract class AbstractRegistry implements IRegistry {
}
@Override
- public List<IRepositoryTag> getTags(String repository) throws DockerException {
- final ClientConfig DEFAULT_CONFIG = new ClientConfig(
- ObjectMapperProvider.class, JacksonFeature.class);
+ public List<IRepositoryTag> getTags(String repository)
+ throws DockerException {
final Client client = ClientBuilder.newClient(DEFAULT_CONFIG);
- WebTarget queryTagsResource;
- List<IRepositoryTag> result = new ArrayList<>();
-
- if (isVersion2()) {
- RepositoryTagV2 crts;
- queryTagsResource = client.target(getHTTPServerAddress()).path("v2") //$NON-NLS-1$
- .path(repository).path("tags").path("list"); //$NON-NLS-1$ //$NON-NLS-2$
- GenericType<RepositoryTagV2> REPOSITORY_TAGS_RESULT_LIST = new GenericType<RepositoryTagV2>() {
- };
- try {
- crts = queryTagsResource.request(APPLICATION_JSON_TYPE).async()
- .method(GET, REPOSITORY_TAGS_RESULT_LIST).get();
- result.addAll(crts.getTags());
- } catch (InterruptedException | ExecutionException e) {
- throw new DockerException(e);
+ try {
+ if (isVersion2()) {
+ return retrieveTagsFromRegistryV2(client, repository);
+ } else if (isDockerHubRegistry()) {
+ return retrieveTagsFromDockerHub(client, repository);
+ } else {
+ return retrieveTagsFromRegistryV1(client, repository);
}
+ } catch (InterruptedException | ExecutionException e) {
+ throw new DockerException(e);
+ }
- // Docker Hub Registry format is actually different from an actual
- // registry
- } else if (isDockerHubRegistry()) {
- queryTagsResource = client.target(getHTTPServerAddress()).path("v1") //$NON-NLS-1$
- .path("repositories").path(repository).path("tags"); //$NON-NLS-1$ //$NON-NLS-2$
- GenericType<List<RepositoryTag>> REPOSITORY_TAGS_RESULT_LIST = new GenericType<List<RepositoryTag>>() {
- };
- try {
- result.addAll(queryTagsResource.request(APPLICATION_JSON_TYPE)
- .async().method(GET, REPOSITORY_TAGS_RESULT_LIST)
- .get());
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- // Do nothing
+ }
+
+ /**
+ * Retrieves the list of tags for a given repository, assuming that the
+ * target registry is Docker Hub.
+ *
+ * @param client
+ * the client to use
+ * @param repository
+ * the repository to look-up
+ * @return the list of tags for the given repository
+ * @throws CancellationException
+ * if the computation was cancelled
+ */
+ private List<IRepositoryTag> retrieveTagsFromDockerHub(final Client client,
+ final String repository)
+ throws DockerException {
+ try {
+ // if the given repository is an official repository, we need to
+ // prepend
+ // with 'library'
+ final String repoName = repository.contains("/") ? repository //$NON-NLS-1$
+ : "library/" + repository; //$NON-NLS-1$
+ // Docker Hub Registry may require a Bearer token which needs to be
+ // retrieved if the initial request returned a 401/Forbidden
+ // response.
+ // In that case, the "Www-Authenticate" response header provides the
+ // information needed to obtain a token.
+ // attempt to query the registry without a bearer token
+ final WebTarget queryTagsResource = client
+ .target(getHTTPServerAddress()).path("v2") //$NON-NLS-1$
+ .path(repoName).path("tags").path("list"); //$NON-NLS-1$ //$NON-NLS-2$
+ // return queryTagsResource.request(APPLICATION_JSON_TYPE).async()
+ // .method(GET, REPOSITORY_TAGS_RESULT_LIST).get();
+ final Response response = queryTagsResource
+ .request(APPLICATION_JSON_TYPE).async().get()
+ .get(10, TimeUnit.SECONDS);
+ if (response.getStatus() == 200) {
+ return response.readEntity(RepositoryTagV2.class).getTags();
+ } else if (response.getStatus() != 401) { // anything but
+ // "Unauthorized"
+ throw new DockerException(
+ NLS.bind(Messages.ImageTagsList_failure, repository,
+ response.readEntity(String.class)));
}
- } else {
- queryTagsResource = client.target(getHTTPServerAddress()).path("v1") //$NON-NLS-1$
- .path("repositories").path(repository).path("tags"); //$NON-NLS-1$ //$NON-NLS-2$
- GenericType<Map<String, String>> REPOSITORY_TAGS_RESULT_LIST = new GenericType<Map<String, String>>() {
- };
- Map<String, String> ret = new HashMap<>();
- try {
- ret = queryTagsResource.request(APPLICATION_JSON_TYPE).async()
- .method(GET, REPOSITORY_TAGS_RESULT_LIST).get();
- for (Entry<String, String> e : ret.entrySet()) {
- RepositoryTag tag = new RepositoryTag();
- tag.setName(e.getKey());
- tag.setLayer(e.getValue());
- result.add(tag);
- }
- } catch (InterruptedException | ExecutionException e) {
- throw new DockerException(e);
+ // for "Unauthorized response, let's get a Bearer token and try
+ // again
+ final String wwwAuthenticateResponseHeader = response
+ .getHeaderString("Www-Authenticate"); //$NON-NLS-1$
+ // parse the header which should have the following form:
+ // Bearer
+ // realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:jboss/wildfly:pull
+ final Map<String, String> authenticateInfo = OAuth2Utils
+ .parseWwwAuthenticateHeader(wwwAuthenticateResponseHeader);
+ if (authenticateInfo == null
+ || !authenticateInfo.containsKey("realm") //$NON-NLS-1$
+ || !authenticateInfo.containsKey("service") //$NON-NLS-1$
+ || !authenticateInfo.containsKey("scope")) { //$NON-NLS-1$
+ throw new DockerException(NLS.bind(
+ Messages.ImageTagsList_failure_invalidWwwAuthenticateFormat,
+ repository));
}
+ // now, call the auth service to obtain a Bearer token:
+ final String realm = authenticateInfo.get("realm"); //$NON-NLS-1$
+ final String service = authenticateInfo.get("service"); //$NON-NLS-1$
+ final String scope = authenticateInfo.get("scope"); //$NON-NLS-1$
+ final WebTarget bearerTokenRetrievalTarget = client.target(realm)
+ .queryParam("service", service) //$NON-NLS-1$
+ .queryParam("scope", scope); //$NON-NLS-1$
+ final BearerTokenResponse bearerTokenRetrievalResponse = bearerTokenRetrievalTarget
+ .request(APPLICATION_JSON_TYPE).async()
+ .get(BearerTokenResponse.class).get(10, TimeUnit.SECONDS);
+ // finally, perform the same request, using the Bearer token:
+ final WebTarget queryTagsResourceWithBearerTokenTarget = client
+ .target(getHTTPServerAddress()).path("v2") //$NON-NLS-1$
+ .path(repoName).path("tags").path("list"); //$NON-NLS-1$ //$NON-NLS-2$
+ return queryTagsResourceWithBearerTokenTarget
+ .request(APPLICATION_JSON_TYPE)
+ .header("Authorization", //$NON-NLS-1$
+ "Bearer " + bearerTokenRetrievalResponse.getToken()) //$NON-NLS-1$
+ .async().get(RepositoryTagV2.class)
+ .get(10, TimeUnit.SECONDS)
+ .getTags();
+ } catch (TimeoutException | ExecutionException
+ | InterruptedException e) {
+ throw new DockerException(NLS.bind(Messages.ImageTagsList_failure,
+ repository, e.getMessage()), e);
}
- return result;
+
+ }
+
+ /**
+ * Retrieves the list of tags for a given repository, assuming that the
+ * target registry is a registry v2 instance.
+ *
+ * @param client
+ * the client to use
+ * @param repository
+ * the repository to look-up
+ * @return the list of tags for the given repository
+ * @throws CancellationException
+ * - if the computation was cancelled
+ * @throws ExecutionException
+ * - if the computation threw an exception
+ * @throws InterruptedException
+ * - if the current thread was interrupted while waiting
+ */
+ private List<IRepositoryTag> retrieveTagsFromRegistryV1(final Client client,
+ final String repository)
+ throws InterruptedException, ExecutionException {
+ final GenericType<Map<String, String>> REPOSITORY_TAGS_RESULT_LIST = new GenericType<Map<String, String>>() {
+ };
+ final WebTarget queryTagsResource = client
+ .target(getHTTPServerAddress()).path("v1") //$NON-NLS-1$
+ .path("repositories").path(repository).path("tags"); //$NON-NLS-1$ //$NON-NLS-2$
+ return queryTagsResource.request(APPLICATION_JSON_TYPE).async()
+ .method(GET, REPOSITORY_TAGS_RESULT_LIST).get().entrySet()
+ .stream().map(e -> new RepositoryTag(e.getKey(), e.getValue()))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Retrieves the list of tags for a given repository, assuming that the
+ * target registry is a registry v1 instance.
+ *
+ * @param client
+ * the client to use
+ * @param repository
+ * the repository to look-up
+ * @return the list of tags for the given repository
+ * @throws CancellationException
+ * - if the computation was cancelled
+ * @throws ExecutionException
+ * - if the computation threw an exception
+ * @throws InterruptedException
+ * - if the current thread was interrupted while waiting
+ */
+ private List<IRepositoryTag> retrieveTagsFromRegistryV2(final Client client,
+ final String repository)
+ throws InterruptedException, ExecutionException {
+ final GenericType<RepositoryTagV2> REPOSITORY_TAGS_RESULT_LIST = new GenericType<RepositoryTagV2>() {
+ };
+ final WebTarget queryTagsResource = client
+ .target(getHTTPServerAddress()).path("v2") //$NON-NLS-1$
+ .path(repository).path("tags").path("list"); //$NON-NLS-1$ //$NON-NLS-2$
+ final RepositoryTagV2 crts = queryTagsResource
+ .request(APPLICATION_JSON_TYPE).async()
+ .method(GET, REPOSITORY_TAGS_RESULT_LIST).get();
+ return crts.getTags();
}
@Override
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerImageBuildFailedException.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerImageBuildFailedException.java
index 35d24b1e3b..d940a6be31 100644
--- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerImageBuildFailedException.java
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/DockerImageBuildFailedException.java
@@ -42,7 +42,7 @@ public class DockerImageBuildFailedException extends DockerException {
public DockerImageBuildFailedException(final String image,
final String message) {
- super(Messages.Image_Build_Failed_Header + image + ": " + message);
+ super(Messages.Image_Build_Failed_Header + image + ": " + message); //$NON-NLS-1$
this.image = image;
}
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IRepositoryTag.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IRepositoryTag.java
index 16a8ed1f0c..4f86ed74b4 100644
--- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IRepositoryTag.java
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/IRepositoryTag.java
@@ -25,4 +25,5 @@ public interface IRepositoryTag {
* @return The corresponding image layer for this specific tag
*/
String getLayer();
+
}
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.java
index e458846be9..5ff5fcb199 100644
--- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.java
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.java
@@ -41,6 +41,8 @@ public class Messages extends NLS {
public static String Docker_Machine_Process_Error;
public static String Docker_Machine_Process_Exception;
public static String Docker_Compose_Command_Not_Found;
+ public static String ImageTagsList_failure;
+ public static String ImageTagsList_failure_invalidWwwAuthenticateFormat;
static {
// Initialize resource bundle.
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.properties b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.properties
index 27b5854825..8bf4462ff0 100644
--- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.properties
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/docker/core/Messages.properties
@@ -35,3 +35,6 @@ Docker_Connection_Timeout=Closing the connection after a timeout exception
Docker_Machine_Process_Error=Failed to execute command ''{0}'' (exit code={1}): {2}
Docker_Machine_Process_Exception=Failed to execute command ''{0}''
Docker_Compose_Command_Not_Found=The '''docker-compose''' command could not be located in {0}
+ImageTagsList_failure=Failed to retrieve the list of tags for the ''{0}'' Docker image: {1}
+ImageTagsList_failure_invalidWwwAuthenticateFormat=Failed to retrieve the list of tags for the ''{0}'' image: unable to parse the "WWW-Authenticate" response header to retrieve a Bearer token.
+
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/OAuth2Utils.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/OAuth2Utils.java
new file mode 100644
index 0000000000..081418e8c4
--- /dev/null
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/OAuth2Utils.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Red Hat.
+ * 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:
+ * Red Hat - Initial Contribution
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.docker.core;
+
+import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
+import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Utility methods related to the OAuth2 Autorization Framework
+ */
+public class OAuth2Utils {
+
+ /**
+ * Parses the given {@code value} similar to
+ * <code>Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:jboss/wildfly:pull"</code>
+ * to extract the <code>realm</code>, <code>service</code> and
+ * <code>scope</code> items.
+ *
+ * @param value
+ * the value to parse
+ * @return a map of the extracted items, or <code>null</code> if the given
+ * {@code value} did not match the expected pattern.
+ */
+ public static Map<String, String> parseWwwAuthenticateHeader(
+ final String value) {
+ final Pattern authHeaderPattern = Pattern.compile(
+ "Bearer realm=\"(?<realm>.+)\",service=\"(?<service>.+)\",scope=\"(?<scope>.+)\""); //$NON-NLS-1$
+ final Matcher matcher = authHeaderPattern.matcher(value);
+ if (!matcher.matches()) {
+ return null;
+ }
+ final Map<String, String> result = new HashMap<>();
+ result.put("realm", matcher.group("realm")); //$NON-NLS-1$ //$NON-NLS-2$
+ result.put("service", matcher.group("service")); //$NON-NLS-1$ //$NON-NLS-2$
+ result.put("scope", matcher.group("scope")); //$NON-NLS-1$ //$NON-NLS-2$
+ return result;
+ }
+
+ @JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
+ public static class BearerTokenResponse {
+
+ @JsonProperty("token") //$NON-NLS-1$
+ private String token;
+
+ public String getToken() {
+ return this.token;
+ }
+
+ public void setToken(final String token) {
+ this.token = token;
+ }
+
+ }
+
+}
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTag.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTag.java
index 657a2a95ae..9cc05c8711 100644
--- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTag.java
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTag.java
@@ -24,7 +24,8 @@ import com.google.common.base.Objects;
*
*/
@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
-public class RepositoryTag implements IRepositoryTag {
+public class RepositoryTag
+ implements IRepositoryTag, Comparable<IRepositoryTag> {
@JsonProperty("layer") //$NON-NLS-1$
private String layer;
@@ -32,6 +33,24 @@ public class RepositoryTag implements IRepositoryTag {
private String name;
/**
+ * Default constructor
+ */
+ public RepositoryTag() {
+ }
+
+ /**
+ * Full constructor.
+ * @param name
+ * the repository name
+ * @param layer
+ * the layer
+ */
+ public RepositoryTag(final String name, final String layer) {
+ this.layer = layer;
+ this.name = name;
+ }
+
+ /**
* @return the layer
*/
@Override
@@ -69,4 +88,73 @@ public class RepositoryTag implements IRepositoryTag {
.add("layer", getLayer()).toString(); //$NON-NLS-1$
}
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((layer == null) ? 0 : layer.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ RepositoryTag other = (RepositoryTag) obj;
+ if (layer == null) {
+ if (other.layer != null) {
+ return false;
+ }
+ } else if (!layer.equals(other.layer)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Compares by the tag 'name' in reverse order.
+ */
+ @Override
+ public int compareTo(final IRepositoryTag other) {
+ // TODO: put this in IRepositoryTag in the next major release.
+ // tries to compare versions in the x.y.z.qualifer format, otherwise,
+ // just do a lexicographical comparison
+ try {
+ final String[] thisParts = this.getName().split("\\."); //$NON-NLS-1$
+ final String[] thatParts = other.getName().split("\\."); //$NON-NLS-1$
+ int length = Math.max(thisParts.length, thatParts.length);
+ for (int i = 0; i < length; i++) {
+ int thisPart = i < thisParts.length
+ ? Integer.parseInt(thisParts[i]) : 0;
+ int thatPart = i < thatParts.length
+ ? Integer.parseInt(thatParts[i]) : 0;
+ if (thisPart < thatPart) {
+ return 1;
+ }
+ if (thisPart > thatPart) {
+ return -1;
+ }
+ }
+ return 0;
+ } catch (NumberFormatException e) {
+ // if one of the name was not a valid version, just do this:
+ return other.getName().compareTo(this.getName());
+ }
+ }
+
}
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2.java
index be06360cc6..53db1e241d 100644
--- a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2.java
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2.java
@@ -13,8 +13,10 @@ package org.eclipse.linuxtools.internal.docker.core;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
-import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.linuxtools.docker.core.IRepositoryTag;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -28,21 +30,21 @@ import com.fasterxml.jackson.annotation.JsonProperty;
@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
public class RepositoryTagV2 {
+ public static final String UNKNOWN_LAYER = "Unknown"; //$NON-NLS-1$
+
@JsonProperty("name") //$NON-NLS-1$
private String name;
@JsonProperty("tags") //$NON-NLS-1$
private List<String> tags;
- public List<RepositoryTag> getTags() {
- List<RepositoryTag> result = new ArrayList<>();
- for (String tag : tags) {
- RepositoryTag rtag = new RepositoryTag();
- rtag.setName(tag);
- rtag.setLayer("Unknown"); //$NON-NLS-1$
- result.add(rtag);
- }
- return result;
+ public List<IRepositoryTag> getTags() {
+ return tags.stream().map(t -> {
+ final RepositoryTag tag = new RepositoryTag();
+ tag.setName(t);
+ tag.setLayer(UNKNOWN_LAYER);
+ return tag;
+ }).collect(Collectors.toList());
}
public String getName() {
diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/docker/core/ImageTagsListTest.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/docker/core/ImageTagsListTest.java
new file mode 100644
index 0000000000..a5efca6cad
--- /dev/null
+++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/docker/core/ImageTagsListTest.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Red Hat.
+ * 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:
+ * Red Hat - Initial Contribution
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.docker.core;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+
+import org.eclipse.linuxtools.internal.docker.core.RegistryInfo;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Testing the logic to retrieve the list of tags from a given Docker image name
+ * (or repository).
+ *
+ * NOTE: tests are ignored because they fail on Hudson (timeout) - need to
+ * verify if the Hudson slave can connect to Docker Hub.
+ */
+@Ignore
+public class ImageTagsListTest {
+
+ private RegistryInfo dockerHubRegistry = new RegistryInfo(AbstractRegistry.DOCKERHUB_REGISTRY, true);
+
+ @Test
+ public void shouldRetrieveTagsForOfficialImage() throws DockerException {
+ // given
+ final String imageName = "php";
+ // when
+ final List<IRepositoryTag> tags = dockerHubRegistry.getTags(imageName);
+ // then
+ assertThat(tags).isNotEmpty();
+ }
+
+ @Test
+ public void shouldRetrieveTagsForRegularImage() throws DockerException {
+ // given
+ final String imageName = "jboss/wildfly";
+ // when
+ final List<IRepositoryTag> tags = dockerHubRegistry.getTags(imageName);
+ // then
+ assertThat(tags).isNotEmpty();
+ }
+
+}
diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/core/OAuth2UtilsTest.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/core/OAuth2UtilsTest.java
new file mode 100644
index 0000000000..71ba623366
--- /dev/null
+++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/core/OAuth2UtilsTest.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Red Hat.
+ * 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:
+ * Red Hat - Initial Contribution
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.docker.core;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Map;
+
+import org.eclipse.linuxtools.internal.docker.core.OAuth2Utils;
+import org.junit.Test;
+
+/**
+ * Testing the pattern to parse a <code>Www-Authenticate</code> response header
+ */
+public class OAuth2UtilsTest {
+
+ @Test
+ public void shouldParseHeader() {
+ // given
+ final String headerValue = "Bearer realm=\"https://auth.docker.io/token\",service=\"registry.docker.io\",scope=\"repository:jboss/wildfly:pull\"";
+ // when
+ final Map<String, String> result = OAuth2Utils.parseWwwAuthenticateHeader(headerValue);
+ // then
+ assertThat(result).hasSize(3).containsEntry("realm", "https://auth.docker.io/token")
+ .containsEntry("service", "registry.docker.io").containsEntry("scope", "repository:jboss/wildfly:pull");
+ }
+
+}
diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2Test.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2Test.java
new file mode 100644
index 0000000000..11ecb416e3
--- /dev/null
+++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/core/RepositoryTagV2Test.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Red Hat.
+ * 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:
+ * Red Hat - Initial Contribution
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.docker.core;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Verifying that a "tags/list" registry response in the V2 format can be
+ * deserialized
+ */
+public class RepositoryTagV2Test {
+
+ @Test
+ public void shouldDeserializeResponseEntity() throws JsonParseException, JsonMappingException, IOException {
+ // given
+ final String responseEntity = "{\"name\":\"jboss/wildfly\",\"tags\":[\"10.0.0.Final\",\"10.1.0.Final\",\"8.1.0.Final\",\"8.2.0.Final\",\"8.2.1.Final\",\"9.0.0.Final\",\"9.0.1.Final\",\"9.0.2.Final\",\"latest\"]}";
+ // when
+ final RepositoryTagV2 result = new ObjectMapper().readValue(responseEntity, RepositoryTagV2.class);
+ // then
+ assertThat(result.getName()).isEqualTo("jboss/wildfly");
+ assertThat(result.getTags()).hasSize(9).contains(new RepositoryTag("latest", RepositoryTagV2.UNKNOWN_LAYER));
+ }
+
+}
diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/testutils/MockContainerFactory.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/testutils/MockContainerFactory.java
index 07883d2813..8410c62b6e 100644
--- a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/testutils/MockContainerFactory.java
+++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/testutils/MockContainerFactory.java
@@ -42,8 +42,6 @@ public class MockContainerFactory {
private static char[] hexa = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
- private static int statusIndex;
-
private final Container container;
private Builder() {
diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/views/DockerImagesViewSWTBotTest.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/views/DockerImagesViewSWTBotTest.java
index 244a86a6db..078363cd69 100644
--- a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/views/DockerImagesViewSWTBotTest.java
+++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/views/DockerImagesViewSWTBotTest.java
@@ -214,8 +214,7 @@ public class DockerImagesViewSWTBotTest {
final DockerConnection dockerConnection = MockDockerConnectionFactory.from("Test", client)
.withDefaultTCPConnectionSettings();
DockerConnectionManagerUtils.configureConnectionManager(dockerConnection);
- final PropertySheet propertySheet = SWTUtils
- .syncExec(() -> SWTUtils.getView(bot, "org.eclipse.ui.views.PropertySheet", true));
+ SWTUtils.syncExec(() -> SWTUtils.getView(bot, "org.eclipse.ui.views.PropertySheet", true));
this.dockerImagesView.setFocus();
// select the container in the table
selectImageInTable("angry_bar");
diff --git a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EditDockerConnectionSWTBotTest.java b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EditDockerConnectionSWTBotTest.java
index 98595a47e2..abe22f0c7d 100644
--- a/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EditDockerConnectionSWTBotTest.java
+++ b/containers/org.eclipse.linuxtools.docker.ui.tests/src/org/eclipse/linuxtools/internal/docker/ui/wizards/EditDockerConnectionSWTBotTest.java
@@ -394,7 +394,7 @@ public class EditDockerConnectionSWTBotTest {
@Test
public void shouldRefreshDockerImagesViewWhenConnectionNameChanges() {
// given
- final IDockerConnection connection = configureTCPConnection("Test");
+ configureTCPConnection("Test");
final SWTBotTreeItem connectionTreeItem = SWTUtils.getTreeItem(dockerExplorer.bot(), "Test");
assertThat(connectionTreeItem).isNotNull();
// when
@@ -411,7 +411,7 @@ public class EditDockerConnectionSWTBotTest {
@Test
public void shouldRefreshDockerContainersViewWhenConnectionNameChanges() {
// given
- final IDockerConnection connection = configureTCPConnection("Test");
+ configureTCPConnection("Test");
final SWTBotTreeItem connectionTreeItem = SWTUtils.getTreeItem(dockerExplorer.bot(), "Test");
assertThat(connectionTreeItem).isNotNull();
// when
@@ -428,7 +428,7 @@ public class EditDockerConnectionSWTBotTest {
@Test
public void shouldRefreshDockerExplorerViewWhenNameChangedTwice() {
// given
- final IDockerConnection connection = configureTCPConnection("Test");
+ configureTCPConnection("Test");
final SWTBotTreeItem connectionTreeItem = SWTUtils.getTreeItem(dockerExplorer.bot(), "Test");
assertThat(connectionTreeItem).isNotNull();
// name change #1
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DockerImageTagSearchResult.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DockerImageTagSearchResult.java
index ace0f6a196..f44cb8fb29 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DockerImageTagSearchResult.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/DockerImageTagSearchResult.java
@@ -70,4 +70,11 @@ public class DockerImageTagSearchResult {
return this.resolved;
}
+ @Override
+ public String toString() {
+ return "DockerImageTagSearchResult [repository=" + repository //$NON-NLS-1$
+ + ", name=" + name + ", layer=" + layer + ", resolved=" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ + resolved + "]"; //$NON-NLS-1$
+ }
+
} \ No newline at end of file
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagPage.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagPage.java
index fe3b5a5458..113e0f95f3 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagPage.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagPage.java
@@ -22,6 +22,9 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
+/**
+ * A {@link WizardPage} to tag a given Docker image.
+ */
public class ImageTagPage extends WizardPage {
private final static String NAME = "ImageTag.name"; //$NON-NLS-1$
@@ -34,6 +37,12 @@ public class ImageTagPage extends WizardPage {
private String tag;
+ /**
+ * Constructor
+ *
+ * @param imageName
+ * the name of the image
+ */
public ImageTagPage(final String imageName) {
super(WizardMessages.getString(NAME));
setTitle(WizardMessages.getString(TITLE));
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagSelectionPage.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagSelectionPage.java
index b972123881..6d52e8d0f5 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagSelectionPage.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/ImageTagSelectionPage.java
@@ -13,10 +13,12 @@ package org.eclipse.linuxtools.internal.docker.ui.wizards;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.BeanProperties;
@@ -35,6 +37,8 @@ import org.eclipse.linuxtools.docker.core.IDockerConnection;
import org.eclipse.linuxtools.docker.core.IRegistry;
import org.eclipse.linuxtools.docker.core.IRepositoryTag;
import org.eclipse.linuxtools.docker.ui.Activator;
+import org.eclipse.linuxtools.internal.docker.core.RepositoryTag;
+import org.eclipse.linuxtools.internal.docker.core.RepositoryTagV2;
import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory;
import org.eclipse.linuxtools.internal.docker.ui.wizards.ImageSearchPage.IconColumnLabelProvider;
import org.eclipse.swt.SWT;
@@ -59,6 +63,8 @@ public class ImageTagSelectionPage extends WizardPage {
*
* @param model
* the model associated to this page
+ * @param registry
+ * the registry on which the search is performed
*/
public ImageTagSelectionPage(final ImageSearchModel model, final IRegistry registry) {
super("ImageTagSelectionPage", //$NON-NLS-1$
@@ -89,19 +95,27 @@ public class ImageTagSelectionPage extends WizardPage {
2);
final String selectedImageName = ImageTagSelectionPage.this.model
.getSelectedImage().getName();
- List<IRepositoryTag> repositoryTags;
try {
- repositoryTags = registry
+ final List<IRepositoryTag> repositoryTags = registry
.getTags(selectedImageName);
+ // we have to convert to list of RepositoryTag which
+ // can be sorted
+ final List<RepositoryTag> tags = repositoryTags
+ .stream()
+ .map(c -> (RepositoryTag) c)
+ .collect(Collectors.toList());
+ Collections.sort(tags);
monitor.worked(1);
- final List<DockerImageTagSearchResult> searchResults = new ArrayList<>();
final IDockerConnection connection = model
.getSelectedConnection();
- for (IRepositoryTag repositoryTag : repositoryTags) {
- searchResults.add(new DockerImageTagSearchResult(
- selectedImageName, repositoryTag,
- connection.hasImage(selectedImageName, repositoryTag.getName())));
- }
+ final List<DockerImageTagSearchResult> searchResults = repositoryTags
+ .stream()
+ .map(t -> new DockerImageTagSearchResult(
+ selectedImageName, t,
+ connection.hasImage(
+ selectedImageName,
+ t.getName())))
+ .collect(Collectors.toList());
monitor.worked(1);
searchResultQueue.offer(searchResults);
} catch (DockerException e) {
@@ -163,6 +177,7 @@ public class ImageTagSelectionPage extends WizardPage {
super.dispose();
}
+ @SuppressWarnings("unchecked")
@Override
public void createControl(final Composite parent) {
final int COLUMNS = 1;
@@ -195,7 +210,7 @@ public class ImageTagSelectionPage extends WizardPage {
SWT.NONE, SWT.LEFT, 75, new ImagePulledColumnLabelProvider());
tableViewer.setContentProvider(new ObservableListContentProvider());
// observe the viewer content
- final IObservableList observableSearchResultModel = BeanProperties
+ final IObservableList<?> observableSearchResultModel = BeanProperties
.list(ImageSearchModel.class,
ImageSearchModel.IMAGE_TAG_SEARCH_RESULT)
.observe(model);
@@ -239,7 +254,12 @@ public class ImageTagSelectionPage extends WizardPage {
@Override
public String getText(final Object element) {
if (element instanceof DockerImageTagSearchResult) {
- return ((DockerImageTagSearchResult) element).getLayer();
+ final String layer = ((DockerImageTagSearchResult) element).getLayer();
+ if (layer == null
+ || layer.equals(RepositoryTagV2.UNKNOWN_LAYER)) {
+ return ""; //$NON-NLS-1$
+ }
+ return layer;
}
return super.getText(element);
}

Back to the top