Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Mylyn/Architecture/Web
The org.eclipse.mylyn.web.core
plug-in provides helper classes for commonly used network operations that are executed by Mylyn connectors. It has utility classes for Apache HttpClient which is used by the connector reference implementations for processing HTTP requests.
The org.eclipse.mylyn.web.core
plug-in can be used in standalone applications and is not coupled to other parts of the Mylyn framework.
Password Prompting
If authentication is required during access of a network resource a callback to the UI to request credentials from the user is required. The AbstractWebLocation
class which is used in the web core plug-in to represent a URL provides the requestCredentials(AuthenticationType, String, IProgressMonitor)
method for that purpose. AuthenticationType
is an enum that specifies the resource to authenticate against, e.g. repository, proxy or http server.
The credentials can be retrieved by invoking getCredentials(AuthenticationType type)
which returns an object of type AuthenticationCredentials
. Currently only username/password credentials are supported:
- Username, Password, (Realm) [HTML Form, HTTP Basic/Digest/NTLM]
- (SSL Certificate)
boolean authenticated = false; while (!authenticated) { AuthenticationCredentials credentials = location.getCredentials(AuthenticationType.REPOSITORY); AuthScope authScope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM); httpClient.getState().setCredentials(authScope, WebUtil.getHttpClientCredentials(credentials, WebUtil.getHost(repositoryUrl))); GetMethod method = new GetMethod(WebUtil.getRequestPath(repositoryUrl + LOGIN_URL)); int code; try { code = WebUtil.execute(httpClient, hostConfiguration, method, monitor); AuthenticationType authenticationType = null; if (code == HttpStatus.SC_UNAUTHORIZED || code == HttpStatus.SC_FORBIDDEN) { authenticationType = AuthenticationType.REPOSITORY; } else if (code == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) { authenticationType = AuthenticationType.PROXY; } else { authenticated = true; } if (!authenticated) { try { location.requestCredentials(authenticationType, null, monitor); } catch (UnsupportedRequestException e) { throw new TracLoginException(); } hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor); } } finally { method.releaseConnection(); } }
The Tasks UI plug-in provides the class TaskRepositoryLocationUi
which supports password management with TaskRepository
objects.
Proxy Support
- HTTP/HTTPS Proxy
- Socks Proxy
Cancellation
The org.eclipse.mylyn.web.core
plug-in helper classes for sending HTTP requests that can be cancelled by a user through the IProgressMonitor
interface. The basic principle is that all network I/O, i.e. opening of sockets, reading and writing of streams, is done on separate threads while the IProgressMonitor
is polled for its cancelled state. If a cancellation is detected the network operation is aborted by closing the socket or stream.
The web core plug-in maintains a thread pool that is shared by all plug-ins using it's API.
Apache HttpClient
Below is an source of the WebUtil.getTitleFromUrl()
method that demonstrates how to send a GET request and parse the response while providing cancellation support.
In order to provide cancellation while a connection is established WebUtil.createHostConfiguration(HttpClient, AbstractWebLocation, IProgressMonitor)
should be used to create a host configuration. The returned host configuration uses a custom socket factory that provides cancellation support while a socket is being connected.
Requests should be executed through WebUtil.execute(HttpClient, HostConfiguration, HttpMethod, IProgressMonitor)
. This method will invoke HttpClient.executeMethod()
and provide cancellation support while the HTTP request is sent and the response is parsed.
For reading the response WebUtil.getResponseBodyAsStream(HttpMethodBase, IProgressMonitor)
should be used which returns an PollingInputStream
that wraps the input stream that is provided by HttpClient and supports cancellation. It is very important to always close the returned input stream in a finally block. If the stream is not closed it will leave a zombie thread which will eventually exhaust the thread pool.
public static String getTitleFromUrl(AbstractWebLocation location, IProgressMonitor monitor) throws IOException, ParseException { monitor = Policy.monitorFor(monitor); try { monitor.beginTask("Retrieving " + location.getUrl(), IProgressMonitor.UNKNOWN); HttpClient client = new HttpClient(); WebUtil.configureHttpClient(client, ""); GetMethod method = new GetMethod(location.getUrl()); try { HostConfiguration hostConfiguration = WebUtil.createHostConfiguration(client, location, monitor); int result = WebUtil.execute(client, hostConfiguration, method, monitor); if (result == HttpStatus.SC_OK) { InputStream in = WebUtil.getResponseBodyAsStream(method, monitor); try { BufferedReader reader = new BufferedReader(new InputStreamReader(in)); HtmlStreamTokenizer tokenizer = new HtmlStreamTokenizer(reader, null); for (Token token = tokenizer.nextToken(); token.getType() != Token.EOF; token = okenizer.nextToken()) { if (token.getType() == Token.TAG) { HtmlTag tag = (HtmlTag) token.getValue(); if (tag.getTagType() == Tag.TITLE) { return getText(tokenizer); } } } } finally { in.close(); } } } finally { method.releaseConnection(); } } finally { monitor.done(); } return null; }
Apache Axis
The JIRA connector uses a customized transport that uses a thread-local variable to keep track of the progress monitor for a particular request. The implementation can be found in JiraHttpSender
and JiraRequest
.