View Javadoc

1   /*
2    * This file is part of Domingo
3    * an Open Source Java-API to Lotus Notes/Domino
4    * hosted at http://domingo.sourceforge.net
5    *
6    * Copyright (c) 2003-2007 Beck et al. projects GmbH Munich, Germany (http://www.bea.de)
7    *
8    * This library is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU Lesser General Public
10   * License as published by the Free Software Foundation; either
11   * version 2.1 of the License, or (at your option) any later version.
12   *
13   * This library is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   * Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public
19   * License along with this library; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21   */
22  
23  package de.bea.domingo.http;
24  
25  import java.io.IOException;
26  import java.io.Serializable;
27  import java.net.MalformedURLException;
28  import java.net.URL;
29  
30  import org.apache.commons.httpclient.Cookie;
31  import org.apache.commons.httpclient.Credentials;
32  import org.apache.commons.httpclient.HostConfiguration;
33  import org.apache.commons.httpclient.HttpClient;
34  import org.apache.commons.httpclient.HttpMethod;
35  import org.apache.commons.httpclient.HttpState;
36  import org.apache.commons.httpclient.HttpStatus;
37  import org.apache.commons.httpclient.URIException;
38  import org.apache.commons.httpclient.UsernamePasswordCredentials;
39  import org.apache.commons.httpclient.auth.AuthScope;
40  import org.apache.commons.httpclient.methods.GetMethod;
41  import org.apache.commons.httpclient.methods.PostMethod;
42  
43  import de.bea.domingo.DNotesMonitor;
44  import de.bea.domingo.monitor.AbstractMonitorEnabled;
45  
46  /***
47   * An Http client for communication with Lotus Domino.
48   *
49   * @author <a href=mailto:kriede@users.sourceforge.net>Kurt Riede</a>
50   */
51  public final class DominoHttpClient extends AbstractMonitorEnabled implements Serializable {
52  
53      /*** serial version ID for serialization. */
54      private static final long serialVersionUID = 1071222474842080977L;
55  
56      /*** Default port of Http protocol. */
57      private static final int DEFAULT_HTTP_PORT = 80;
58  
59      private Credentials fCredentials;
60  
61      private String fProtocol = "http:";
62  
63      private String fHost;
64  
65      private int fPort = DEFAULT_HTTP_PORT;
66  
67      private String fUsername;
68  
69      private String fPassword;
70  
71      /*** List of {@link org.apache.commons.httpclient.Cookie}s. */
72  //    private List fCookies = new ArrayList();
73  
74      private HttpClient fHttpClient;
75  
76      /***
77       * Constructor.
78       *
79       * @param monitor the monitor
80       * @param host the host for the session to connect
81       * @param username the username for login
82       * @param password the password for login
83       * @throws MalformedURLException if the host is not valid
84       */
85      public DominoHttpClient(final DNotesMonitor monitor, final String host, final String username, final String password)
86              throws MalformedURLException {
87          super(monitor);
88          final String urlStr = (host.indexOf(':') < 0) ? "http://" + host : host;
89          final URL url = new URL(urlStr);
90          fProtocol = url.getProtocol();
91          if (!"http".equals(fProtocol) && !"https".equals(fProtocol)) {
92              throw new NotesHttpRuntimeException("protocol not supported: " + fProtocol);
93          }
94          fHost = url.getHost();
95          fPort = url.getPort();
96          fPort = fPort == -1 ? DEFAULT_HTTP_PORT : fPort;
97          fUsername = username;
98          fPassword = password;
99          fHttpClient = new HttpClient();
100         DominoPreferences prefs = new DominoPreferences(fHost);
101         fHttpClient.getState().addCookie(prefs.getTimeZoneCookie());
102         fHttpClient.getState().addCookie(prefs.getRegionalCookie());
103     }
104 
105     /***
106      * Login to the Lotus Domino server.
107      *
108      * @throws IOException if the login fails
109      */
110     public void login() throws IOException {
111         loginBasicAuthentication();
112         loginSessionAuthentication();
113     }
114 
115     private void loginBasicAuthentication() throws IOException {
116         fCredentials = new UsernamePasswordCredentials(fUsername, fPassword);
117         fHttpClient.getState().setCredentials(new AuthScope(fHost, fPort, AuthScope.ANY_REALM), fCredentials);
118 
119         // TODO test this: Http request to ensure server is available
120 //        DominoGetMethod method = createGetMethod(fProtocol + "://" + fHost + ":" + fPort + "/" + "names.nsf");
121 //        final int statusCode = executeMethod(method);
122 //        if (statusCode != HttpStatus.SC_OK) {
123 //            getMonitor().error("Http request failed: " + method.getStatusText());
124 //            throw new NotesHttpRuntimeException("Error " + method.getStatusCode() + ": " + method.getStatusText());
125 //        }
126 //        final byte[] responseBody = method.getResponseBody();
127 //        if (new String(responseBody).indexOf("Session valid") < 0) {
128 //            throw new NotesHttpRuntimeException("Invalid Session");
129 //        }
130     }
131 
132     private void loginSessionAuthentication() throws IOException {
133         final String url = fProtocol + "://" + fHost + ":" + fPort + "/" + "names.nsf?Login";
134         final PostMethod method = new PostMethod(url);
135         method.addParameter("%%ModDate", "0000000000000000");
136         method.addParameter("Username", fUsername);
137         method.addParameter("Password", fPassword);
138         method.addParameter("RedirectTo", "/names.nsf");
139         try {
140             getMonitor().debug("Session authentication with " + url);
141             final int statusCode = fHttpClient.executeMethod(method);
142             if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_MOVED_TEMPORARILY) {
143                 getMonitor().error("Http request failed: " + method.getStatusLine());
144             }
145             // TODO check if a valid session cookie is now available
146 //            setCookies(method.getResponseHeaders("Set-Cookie"));
147             logCookies();
148         } catch (IOException e) {
149             getMonitor().error(e.getLocalizedMessage(), e);
150             throw e;
151         } finally {
152             method.releaseConnection();
153         }
154     }
155 
156     /***
157      * Returns the protocol for the connection, either <tt>http</tt> or
158      * <tt>https</tt>.
159      *
160      * @return protocol
161      */
162     public String getProtocol() {
163         return fProtocol;
164     }
165 
166     /***
167      * Returns the host name of the server.
168      *
169      * @return host name
170      */
171     public String getHost() {
172         return fHost;
173     }
174 
175     /***
176      * Returns the port of the server.
177      *
178      * @return port
179      */
180     public int getPort() {
181         return fPort;
182     }
183 
184     /***
185      * Returns the current user name.
186      *
187      * @return username
188      */
189     public String getUserName() {
190         return fUsername;
191     }
192 
193     /***
194      * Returns the name of the current user in the common format.
195      *
196      * @return username in common format
197      */
198     public String getCommonUserName() {
199         // TODO convert user name format
200         return fUsername;
201     }
202 
203     /***
204      * Returns the name of the current user in the canonical format.
205      *
206      * @return username in canonical format
207      */
208     public String getCanonicalUserName() {
209         // TODO convert user name format
210         return fUsername;
211     }
212 
213     /***
214      * Executes the given {@link HttpMethod HTTP method} using the given custom
215      * {@link HostConfiguration host configuration} with the given custom
216      * {@link HttpState HTTP state}.
217      *
218      * @param hostConfiguration The {@link HostConfiguration host configuration}
219      *            to use. If <code>null</code>, the host configuration
220      *            returned by {@link HttpClient#getHostConfiguration()} will be used
221      * @param method the {@link HttpMethod HTTP method} to execute.
222      * @param state the {@link HttpState HTTP state} to use when executing the
223      *            method. If <code>null</code>, the state returned by
224      *            {@link HttpClient#getState()} will be used.
225      * @return the method's response code
226      *
227      * @throws IOException If an I/O (transport) error occurs. Some transport
228      *             exceptions can be recovered from.
229      */
230     public int executeMethod(final HostConfiguration hostConfiguration, final HttpMethod method, final HttpState state)
231             throws IOException {
232         logMethod(method);
233         return fHttpClient.executeMethod(hostConfiguration, method, state);
234     }
235 
236     /***
237      * Executes the given {@link HttpMethod HTTP method} using custom
238      * {@link HostConfiguration host configuration}.
239      *
240      * @param hostConfiguration The {@link HostConfiguration host configuration}
241      *            to use. If <code>null</code>, the host configuration
242      *            returned by {@link HttpClient#getHostConfiguration()} will be used
243      * @param method the {@link HttpMethod HTTP method} to execute
244      * @return the method's response code
245      *
246      * @throws IOException If an I/O (transport) error occurs. Some transport
247      *             exceptions can be recovered from.
248      */
249     public int executeMethod(final HostConfiguration hostConfiguration, final HttpMethod method) throws IOException {
250         logMethod(method);
251         return fHttpClient.executeMethod(hostConfiguration, method);
252     }
253 
254     /***
255      * Executes the given {@link HttpMethod HTTP method}.
256      *
257      * @param method the {@link HttpMethod HTTP method} to execute
258      * @return the method's response code
259      *
260      * @throws IOException If an I/O (transport) error occurs. Some transport
261      *             exceptions can be recovered from.
262      */
263     public int executeMethod(final DominoHttpMethod method) throws IOException {
264         logMethod(method);
265         return fHttpClient.executeMethod(method);
266     }
267 
268 //    private void setCookies(final HttpMethod method) {
269 //        for (int i = 0; i < fCookies.size(); i++) {
270 //            method.addRequestHeader((Header) fCookies.get(i));
271 //        }
272 //    }
273 //
274 //    private void setCookies(final Header[] cookies) {
275 //        for (int i = 0; i < cookies.length; i++) {
276 //            fCookies.add(cookies[i]);
277 //        }
278 //    }
279 
280     private void logMethod(final HttpMethod method) throws URIException {
281         if (method instanceof GetMethod) {
282             getMonitor().debug("HTTP GET " + method.getURI());
283         } else if (method instanceof GetMethod) {
284             getMonitor().debug("HTTP POST " + method.getURI());
285         }
286         logCookies();
287     }
288 
289     private void logCookies() {
290         if (getMonitor().isDebugEnabled()) {
291             Cookie[] cookies = fHttpClient.getState().getCookies();
292             for (int i = 0; i < cookies.length; i++) {
293                 Cookie cookie = (Cookie) cookies[i];
294                 getMonitor().debug(cookie.getName() + ": " + cookie.getValue());
295             }
296         }
297     }
298 
299     /***
300      * Creates and returns a new Http POST method.
301      *
302      * @param pathInfo the path on the server
303      * @return new POST method
304      */
305     public DominoPostMethod createPost(final String pathInfo) {
306         final String url = fProtocol + "://" + fHost + ":" + fPort + "/" + pathInfo;
307         return DominoPostMethod.getInstance(url);
308     }
309 
310     /***
311      * Creates and returns a new Http GET method.
312      *
313      * @param pathInfo the path on the server
314      * @return new GET method
315      */
316     public DominoGetMethod createGetMethod(final String pathInfo) {
317         final String url = fProtocol + "://" + fHost + ":" + fPort + "/" + pathInfo;
318         return DominoGetMethod.getInstance(url);
319     }
320 }