View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.client;
20  
21  import java.io.BufferedReader;
22  import java.io.BufferedWriter;
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.OutputStream;
30  import java.io.OutputStreamWriter;
31  import java.util.ArrayList;
32  import java.util.Collections;
33  import java.util.LinkedHashMap;
34  import java.util.List;
35  import java.util.Locale;
36  import java.util.Map;
37  
38  import org.apache.chemistry.opencmis.client.api.ObjectFactory;
39  import org.apache.chemistry.opencmis.client.api.SessionFactory;
40  import org.apache.chemistry.opencmis.commons.SessionParameter;
41  import org.apache.chemistry.opencmis.commons.enums.BindingType;
42  import org.apache.chemistry.opencmis.commons.server.CmisServiceFactory;
43  import org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider;
44  
45  /**
46   * A map with convenience methods to set session parameters.
47   * <p>
48   * Sample code:
49   * </p>
50   * 
51   * <pre>
52   * SessionFactory factory = ...
53   * 
54   * SessionParameterMap parameter = new SessionParameterMap();
55   * 
56   * parameter.setBasicAuthentication("Otto", "****");
57   * parameter.setAtomPubBindingUrl("http://localhost/cmis/atom");
58   * parameter.setRepositoryId("myRepository");
59   * ...
60   * Session session = factory.createSession(parameter);
61   * </pre>
62   * 
63   * 
64   * @see SessionParameter
65   * @see SessionFactory
66   */
67  public class SessionParameterMap extends LinkedHashMap<String, String> {
68  
69      private static final long serialVersionUID = 1L;
70  
71      /**
72       * Creates an empty map.
73       */
74      public SessionParameterMap() {
75          super();
76      }
77  
78      /**
79       * Creates a map with the same mappings as the specified map.
80       * 
81       * @param map
82       *            the map whose mappings are to be placed in this map
83       */
84      public SessionParameterMap(Map<? extends String, ? extends String> map) {
85          super(map);
86      }
87  
88      /**
89       * Sets a long value.
90       * 
91       * @param key
92       *            the key
93       * @param value
94       *            the value
95       * 
96       * @return the previous value for this key or {@code null}
97       */
98      public String put(String key, long value) {
99          return put(key, Long.toString(value));
100     }
101 
102     /**
103      * Sets a boolean value.
104      * 
105      * @param key
106      *            the key
107      * @param value
108      *            the value
109      * 
110      * @return the previous value for this key or {@code null}
111      */
112     public String put(String key, boolean value) {
113         return put(key, value ? "true" : "false");
114     }
115 
116     /**
117      * Sets the AtomPub URL and sets the binding to AtomPub.
118      * 
119      * @param url
120      *            the AtomPub binding URL
121      */
122     public void setAtomPubBindingUrl(String url) {
123         if (url == null) {
124             remove(SessionParameter.BINDING_TYPE);
125             remove(SessionParameter.ATOMPUB_URL);
126         } else {
127             put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
128             put(SessionParameter.ATOMPUB_URL, url);
129         }
130     }
131 
132     /**
133      * Sets the Web Services WSDL URL and sets the binding to Web Services.
134      * Assumes that all CMIS services have the same WSDL URL.
135      * 
136      * @param url
137      *            the Web Services WSDL URL
138      */
139     public void setWebServicesBindingUrl(String url) {
140         if (url == null) {
141             remove(SessionParameter.BINDING_TYPE);
142             remove(SessionParameter.WEBSERVICES_REPOSITORY_SERVICE);
143             remove(SessionParameter.WEBSERVICES_NAVIGATION_SERVICE);
144             remove(SessionParameter.WEBSERVICES_OBJECT_SERVICE);
145             remove(SessionParameter.WEBSERVICES_VERSIONING_SERVICE);
146             remove(SessionParameter.WEBSERVICES_DISCOVERY_SERVICE);
147             remove(SessionParameter.WEBSERVICES_MULTIFILING_SERVICE);
148             remove(SessionParameter.WEBSERVICES_RELATIONSHIP_SERVICE);
149             remove(SessionParameter.WEBSERVICES_ACL_SERVICE);
150             remove(SessionParameter.WEBSERVICES_POLICY_SERVICE);
151         } else {
152             put(SessionParameter.BINDING_TYPE, BindingType.WEBSERVICES.value());
153             put(SessionParameter.WEBSERVICES_REPOSITORY_SERVICE, url);
154             put(SessionParameter.WEBSERVICES_NAVIGATION_SERVICE, url);
155             put(SessionParameter.WEBSERVICES_OBJECT_SERVICE, url);
156             put(SessionParameter.WEBSERVICES_VERSIONING_SERVICE, url);
157             put(SessionParameter.WEBSERVICES_DISCOVERY_SERVICE, url);
158             put(SessionParameter.WEBSERVICES_MULTIFILING_SERVICE, url);
159             put(SessionParameter.WEBSERVICES_RELATIONSHIP_SERVICE, url);
160             put(SessionParameter.WEBSERVICES_ACL_SERVICE, url);
161             put(SessionParameter.WEBSERVICES_POLICY_SERVICE, url);
162         }
163     }
164 
165     /**
166      * Sets the Web Service memory threshold.
167      * 
168      * @param threshold
169      *            the threshold in bytes
170      */
171     public void setWebServicesMemoryThreshold(long threshold) {
172         put(SessionParameter.WEBSERVICES_MEMORY_THRESHOLD, threshold);
173     }
174 
175     /**
176      * Sets the Web Service temp directory.
177      * 
178      * @param tempDir
179      *            path of the temp directory
180      * @param encrypt
181      *            {@code true} if temp files should be encrypted, {@code false}
182      *            otherwise
183      */
184     public void setWebServicesMemoryTempDirectory(String tempDir, boolean encrypt) {
185         if (tempDir == null) {
186             remove(SessionParameter.WEBSERVICES_TEMP_DIRECTORY);
187             remove(SessionParameter.WEBSERVICES_TEMP_ENCRYPT);
188         } else {
189             put(SessionParameter.WEBSERVICES_TEMP_DIRECTORY, tempDir);
190             put(SessionParameter.WEBSERVICES_TEMP_ENCRYPT, encrypt);
191         }
192     }
193 
194     /**
195      * Sets the Browser URL and sets the binding to Browser.
196      * 
197      * @param url
198      *            the Browser binding URL
199      */
200     public void setBrowserBindingUrl(String url) {
201         if (url == null) {
202             remove(SessionParameter.BINDING_TYPE);
203             remove(SessionParameter.BROWSER_URL);
204         } else {
205             put(SessionParameter.BINDING_TYPE, BindingType.BROWSER.value());
206             put(SessionParameter.BROWSER_URL, url);
207         }
208     }
209 
210     /**
211      * Sets whether properties should be sent in the succinct format or not.
212      * Only relevant for the browser binding.
213      * 
214      * @param succinct
215      *            {@code true} if properties should be sent in the succinct
216      *            format, {@code false} otherwise
217      */
218     public void setBrowserBindingSuccinct(boolean succinct) {
219         put(SessionParameter.BROWSER_SUCCINCT, succinct);
220     }
221 
222     /**
223      * Sets the local service factory and sets the binding to Local.
224      * 
225      * @param serviceFactoryClass
226      *            the local service factory class
227      */
228     public void setLocalBindingClass(Class<? extends CmisServiceFactory> serviceFactoryClass) {
229         if (serviceFactoryClass == null) {
230             remove(SessionParameter.BINDING_TYPE);
231             remove(SessionParameter.LOCAL_FACTORY);
232         } else {
233             put(SessionParameter.BINDING_TYPE, BindingType.LOCAL.value());
234             put(SessionParameter.LOCAL_FACTORY, serviceFactoryClass.getName());
235         }
236     }
237 
238     /**
239      * Sets the repository ID.
240      * 
241      * @param repositoryId
242      *            the repository ID
243      */
244     public void setRepositoryId(String repositoryId) {
245         if (repositoryId == null) {
246             remove(SessionParameter.REPOSITORY_ID);
247         } else {
248             put(SessionParameter.REPOSITORY_ID, repositoryId);
249         }
250     }
251 
252     /**
253      * Sets user and password.
254      * 
255      * @param user
256      *            the user
257      * @param password
258      *            the password
259      */
260     public void setUserAndPassword(String user, String password) {
261         if (user == null) {
262             remove(SessionParameter.USER);
263             remove(SessionParameter.PASSWORD);
264         } else {
265             put(SessionParameter.USER, user);
266             put(SessionParameter.PASSWORD, password);
267         }
268     }
269 
270     /**
271      * Sets bearer token.
272      * 
273      * @param token
274      *            the bearer token
275      */
276     public void setBearerToken(String token) {
277         if (token == null) {
278             remove(SessionParameter.OAUTH_ACCESS_TOKEN);
279         } else {
280             put(SessionParameter.OAUTH_ACCESS_TOKEN, token);
281         }
282     }
283 
284     /**
285      * Turns all authentication off if the standard authentication provider is
286      * used.
287      */
288     public void setNoAuthentication() {
289         put(SessionParameter.AUTH_HTTP_BASIC, false);
290         put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
291         put(SessionParameter.AUTH_OAUTH_BEARER, false);
292 
293         remove(SessionParameter.AUTHENTICATION_PROVIDER_CLASS);
294     }
295 
296     /**
297      * Turns basic authentication on and UsernameToken authentication off if the
298      * standard authentication provider is used.
299      * 
300      * @param user
301      *            the user
302      * 
303      * @param password
304      *            the password
305      */
306     public void setBasicAuthentication(String user, String password) {
307         if (user == null) {
308             throw new IllegalArgumentException("User must be set!");
309         }
310 
311         setUserAndPassword(user, password);
312         setBasicAuthentication();
313     }
314 
315     /**
316      * Turns basic authentication on and UsernameToken authentication off if the
317      * standard authentication provider is used.
318      */
319     public void setBasicAuthentication() {
320         put(SessionParameter.AUTH_HTTP_BASIC, true);
321         put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
322         put(SessionParameter.AUTH_OAUTH_BEARER, false);
323 
324         remove(SessionParameter.AUTHENTICATION_PROVIDER_CLASS);
325     }
326 
327     /**
328      * Turns UsernameToken authentication on for the Web Services binding if the
329      * standard authentication provider is used.
330      * 
331      * @param user
332      *            the user
333      * @param password
334      *            the password
335      * @param basicAuth
336      *            {@code true} if basic authentication should be used in
337      *            addition to the UsernameToken authentication (required by some
338      *            servers), {@code false} otherwise
339      */
340     public void setUsernameTokenAuthentication(String user, String password, boolean basicAuth) {
341         if (user == null) {
342             throw new IllegalArgumentException("User must be set!");
343         }
344 
345         setUserAndPassword(user, password);
346         setUsernameTokenAuthentication(basicAuth);
347     }
348 
349     /**
350      * Turns UsernameToken authentication on for the Web Services binding if the
351      * standard authentication provider is used.
352      * 
353      * @param basicAuth
354      *            {@code true} if basic authentication should be used in
355      *            addition to the UsernameToken authentication (required by some
356      *            servers), {@code false} otherwise
357      */
358     public void setUsernameTokenAuthentication(boolean basicAuth) {
359         put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, true);
360         put(SessionParameter.AUTH_HTTP_BASIC, basicAuth);
361         put(SessionParameter.AUTH_OAUTH_BEARER, false);
362 
363         remove(SessionParameter.AUTHENTICATION_PROVIDER_CLASS);
364     }
365 
366     /**
367      * Turns NTLM authentication on and basic authentication and UsernameToken
368      * authentication off.
369      * <p>
370      * <em>Works only in single user environments and only with NTLMv1!</em>
371      * 
372      * @param user
373      *            the user
374      * @param password
375      *            the password
376      */
377     public void setNtlmAuthentication(String user, String password) {
378         if (user == null) {
379             throw new IllegalArgumentException("User must be set!");
380         }
381 
382         setUserAndPassword(user, password);
383         setNtlmAuthentication();
384     }
385 
386     /**
387      * Turns NTLM authentication on and basic authentication and UsernameToken
388      * authentication off.
389      * <p>
390      * <em>Works only in single user environments and only with NTLMv1!</em>
391      */
392     public void setNtlmAuthentication() {
393         put(SessionParameter.AUTH_HTTP_BASIC, false);
394         put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
395         put(SessionParameter.AUTH_OAUTH_BEARER, false);
396 
397         put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS,
398                 "org.apache.chemistry.opencmis.client.bindings.spi.NTLMAuthenticationProvider");
399     }
400 
401     /**
402      * Turns Client Certificate authentication on and and basic authentication
403      * and UsernameToken authentication off.
404      * 
405      * @param keyfilePath
406      *            the path to the JKS key file
407      * @param passphrase
408      *            the pass phrase for the key file
409      */
410     public void setCertificateAuthentication(String keyfilePath, String passphrase) {
411         if (keyfilePath == null) {
412             throw new IllegalArgumentException("Key file path mut be set!");
413         }
414 
415         put(SessionParameter.AUTH_HTTP_BASIC, false);
416         put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
417         put(SessionParameter.AUTH_OAUTH_BEARER, false);
418 
419         put(SessionParameter.CLIENT_CERT_KEYFILE, keyfilePath);
420         if (passphrase == null) {
421             remove(SessionParameter.CLIENT_CERT_PASSPHRASE);
422         } else {
423             put(SessionParameter.CLIENT_CERT_PASSPHRASE, passphrase);
424         }
425 
426         put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS,
427                 "org.apache.chemistry.opencmis.client.bindings.spi.ClientCertificateAuthenticationProvider");
428     }
429 
430     /**
431      * Turns simple OAuth 2.0 bearer token authentication on and basic
432      * authentication and UsernameToken authentication off.
433      * <p>
434      * This authentication method does not refresh the token when it expires.
435      * 
436      * @param token
437      *            the bearer token
438      */
439     public void setOAuthBearerTokenAuthentication(String token) {
440         if (token == null) {
441             throw new IllegalArgumentException("Token must be set!");
442         }
443 
444         setBearerToken(token);
445 
446         put(SessionParameter.AUTH_HTTP_BASIC, false);
447         put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
448         put(SessionParameter.AUTH_OAUTH_BEARER, true);
449         put(SessionParameter.OAUTH_ACCESS_TOKEN, token);
450 
451         remove(SessionParameter.AUTHENTICATION_PROVIDER_CLASS);
452     }
453 
454     /**
455      * Turns OAuth 2.0 authentication on and basic authentication and
456      * UsernameToken authentication off.
457      * <p>
458      * This authentication method requests a new token and refreshes the token
459      * when it expires.
460      * 
461      * @param tokenEntpoint
462      *            the token endpoint URL
463      * @param clientId
464      *            the client ID
465      * @param clientSecret
466      *            the client secret if required, {@code null} otherwise
467      * @param code
468      *            the authorization code
469      * @param redirectUri
470      *            the redirect URI if required, {@code null} otherwise
471      */
472     public void setOAuthAuthentication(String tokenEntpoint, String clientId, String clientSecret, String code,
473             String redirectUri) {
474         if (tokenEntpoint == null || tokenEntpoint.length() == 0) {
475             throw new IllegalArgumentException("Token endpoint must be set!");
476         }
477 
478         if (clientId == null || clientId.length() == 0) {
479             throw new IllegalArgumentException("Client ID must be set!");
480         }
481 
482         put(SessionParameter.OAUTH_TOKEN_ENDPOINT, tokenEntpoint);
483         put(SessionParameter.OAUTH_CLIENT_ID, clientId);
484 
485         if (clientSecret == null) {
486             remove(SessionParameter.OAUTH_CLIENT_SECRET);
487         } else {
488             put(SessionParameter.OAUTH_CLIENT_SECRET, clientSecret);
489         }
490 
491         if (code == null) {
492             remove(SessionParameter.OAUTH_CODE);
493         } else {
494             put(SessionParameter.OAUTH_CODE, code);
495         }
496 
497         if (redirectUri == null) {
498             remove(SessionParameter.OAUTH_REDIRECT_URI);
499         } else {
500             put(SessionParameter.OAUTH_REDIRECT_URI, redirectUri);
501         }
502 
503         setOAuthAuthentication();
504     }
505 
506     /**
507      * Turns OAuth 2.0 authentication on and basic authentication and
508      * UsernameToken authentication off.
509      * <p>
510      * This authentication method uses the provided token and refreshes the
511      * token when it expires.
512      * 
513      * @param tokenEntpoint
514      *            the token endpoint URL
515      * @param clientId
516      *            the client ID
517      * @param clientSecret
518      *            the client secret if required, {@code null} otherwise
519      * @param accessToken
520      *            the bearer access token
521      * @param refreshToken
522      *            the refresh token
523      * @param expirationTimestamp
524      *            the timestamp when the access token expires
525      */
526     public void setOAuthAuthentication(String tokenEntpoint, String clientId, String clientSecret, String accessToken,
527             String refreshToken, long expirationTimestamp) {
528         if (tokenEntpoint == null || tokenEntpoint.length() == 0) {
529             throw new IllegalArgumentException("Token endpoint must be set!");
530         }
531 
532         if (clientId == null || clientId.length() == 0) {
533             throw new IllegalArgumentException("Client ID must be set!");
534         }
535 
536         put(SessionParameter.OAUTH_TOKEN_ENDPOINT, tokenEntpoint);
537         put(SessionParameter.OAUTH_CLIENT_ID, clientId);
538 
539         if (clientSecret == null) {
540             remove(SessionParameter.OAUTH_CLIENT_SECRET);
541         } else {
542             put(SessionParameter.OAUTH_CLIENT_SECRET, clientSecret);
543         }
544 
545         if (accessToken == null) {
546             remove(SessionParameter.OAUTH_ACCESS_TOKEN);
547         } else {
548             put(SessionParameter.OAUTH_ACCESS_TOKEN, accessToken);
549         }
550 
551         if (refreshToken == null) {
552             remove(SessionParameter.OAUTH_REFRESH_TOKEN);
553         } else {
554             put(SessionParameter.OAUTH_REFRESH_TOKEN, refreshToken);
555         }
556 
557         if (expirationTimestamp < 0) {
558             remove(SessionParameter.OAUTH_EXPIRATION_TIMESTAMP);
559         } else {
560             put(SessionParameter.OAUTH_EXPIRATION_TIMESTAMP, expirationTimestamp);
561         }
562 
563         setOAuthAuthentication();
564     }
565 
566     /**
567      * Turns OAuth 2.0 authentication on and basic authentication and
568      * UsernameToken authentication off.
569      */
570     public void setOAuthAuthentication() {
571         put(SessionParameter.AUTH_HTTP_BASIC, false);
572         put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, false);
573         put(SessionParameter.AUTH_OAUTH_BEARER, false);
574 
575         put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS,
576                 "org.apache.chemistry.opencmis.client.bindings.spi.OAuthAuthenticationProvider");
577     }
578 
579     /**
580      * Sets the locale of the session.
581      * 
582      * @param locale
583      *            the locale
584      */
585     public void setLocale(Locale locale) {
586         if (locale == null) {
587             remove(SessionParameter.LOCALE_ISO639_LANGUAGE);
588             remove(SessionParameter.LOCALE_ISO3166_COUNTRY);
589             remove(SessionParameter.LOCALE_VARIANT);
590         } else {
591             if (locale.getLanguage().length() == 0) {
592                 remove(SessionParameter.LOCALE_ISO639_LANGUAGE);
593             } else {
594                 put(SessionParameter.LOCALE_ISO639_LANGUAGE, locale.getLanguage());
595             }
596             if (locale.getCountry().length() == 0) {
597                 remove(SessionParameter.LOCALE_ISO3166_COUNTRY);
598             } else {
599                 put(SessionParameter.LOCALE_ISO3166_COUNTRY, locale.getCountry());
600             }
601             if (locale.getVariant().length() == 0) {
602                 remove(SessionParameter.LOCALE_VARIANT);
603             } else {
604                 put(SessionParameter.LOCALE_VARIANT, locale.getVariant());
605             }
606         }
607     }
608 
609     /**
610      * Sets the locale of the session.
611      * 
612      * @param language
613      *            ISO 639 language code
614      * @param country
615      *            ISO 3166 country code
616      */
617     public void setLocale(String language, String country) {
618         setLocale(new Locale(language, country));
619     }
620 
621     /**
622      * Sets the locale of the session.
623      * 
624      * @param language
625      *            ISO 639 language code
626      */
627     public void setLocale(String language) {
628         setLocale(new Locale(language));
629     }
630 
631     /**
632      * Sets the JVM default locale of the session.
633      */
634     public void setDefaultLocale() {
635         setLocale(Locale.getDefault());
636     }
637 
638     /**
639      * Sets whether cookies should be managed or not.
640      * 
641      * @param cookies
642      *            {@code true} if cookies should be managed, {@code false}
643      *            otherwise
644      */
645     public void setCookies(boolean cookies) {
646         put(SessionParameter.COOKIES, cookies);
647     }
648 
649     /**
650      * Sets if the server should be asked to use compression.
651      * 
652      * @param compression
653      *            {@code true} if the server should be asked to use compression,
654      *            {@code false} otherwise
655      */
656     public void setCompression(boolean compression) {
657         put(SessionParameter.COMPRESSION, compression);
658     }
659 
660     /**
661      * Sets the user agent string.
662      * 
663      * @param userAgent
664      *            the user agent string
665      */
666     public void setUserAgent(String userAgent) {
667         if (userAgent != null) {
668             put(SessionParameter.USER_AGENT, userAgent);
669         } else {
670             remove(SessionParameter.USER_AGENT);
671         }
672     }
673 
674     /**
675      * Sets whether requests to the server should be compressed or not.
676      * 
677      * @param compression
678      *            {@code true} if requests should be compressed, {@code false}
679      *            otherwise
680      */
681     public void setClientCompression(boolean compression) {
682         put(SessionParameter.CLIENT_COMPRESSION, compression);
683     }
684 
685     /**
686      * Sets the CSRF HTTP header
687      * 
688      * @param csrfHeader
689      *            name of the CSRF header
690      */
691     public void setCsrfHeader(String csrfHeader) {
692         if (csrfHeader != null) {
693             put(SessionParameter.CSRF_HEADER, csrfHeader);
694         } else {
695             remove(SessionParameter.CSRF_HEADER);
696         }
697     }
698 
699     /**
700      * Sets the HTTP connection timeout.
701      * 
702      * @param timeout
703      *            the connection timeout in milliseconds
704      */
705     public void setConnectionTimeout(long timeout) {
706         put(SessionParameter.CONNECT_TIMEOUT, timeout);
707     }
708 
709     /**
710      * Sets the HTTP read timeout.
711      * 
712      * @param timeout
713      *            the read timeout in milliseconds
714      */
715     public void setReadTimeout(long timeout) {
716         put(SessionParameter.READ_TIMEOUT, timeout);
717     }
718 
719     /**
720      * Sets the HTTP invoker class.
721      * 
722      * @param httpInvokerClass
723      *            the HTTP invoker class
724      */
725     public void setHttpInvoker(Class<?> httpInvokerClass) {
726         if (httpInvokerClass == null) {
727             remove(SessionParameter.HTTP_INVOKER_CLASS);
728         } else {
729             put(SessionParameter.HTTP_INVOKER_CLASS, httpInvokerClass.getName());
730         }
731     }
732 
733     /**
734      * Adds a HTTP header.
735      * 
736      * @param header
737      *            the header name
738      * @param value
739      *            the header value
740      */
741     public void addHeader(String header, String value) {
742         if (header == null || header.trim().length() == 0) {
743             return;
744         }
745 
746         int x = 0;
747         while (containsKey(SessionParameter.HEADER + "." + x)) {
748             x++;
749         }
750 
751         put(SessionParameter.HEADER + "." + x, header + ":" + value);
752     }
753 
754     /**
755      * Sets HTTP proxy user and password.
756      * 
757      * @param user
758      *            the user
759      * @param password
760      *            the password
761      */
762     public void setProxyUserAndPassword(String user, String password) {
763         if (user == null) {
764             remove(SessionParameter.PROXY_USER);
765             remove(SessionParameter.PROXY_PASSWORD);
766         } else {
767             put(SessionParameter.PROXY_USER, user);
768             put(SessionParameter.PROXY_PASSWORD, password);
769         }
770     }
771 
772     /**
773      * Sets the authentication provider class.
774      * 
775      * @param authenticationProviderClass
776      *            the authentication provider class
777      */
778     public void setAuthenticationProvider(Class<? extends AuthenticationProvider> authenticationProviderClass) {
779         if (authenticationProviderClass == null) {
780             remove(SessionParameter.AUTHENTICATION_PROVIDER_CLASS);
781         } else {
782             put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS, authenticationProviderClass.getName());
783         }
784     }
785 
786     /**
787      * Sets the object factory class.
788      * 
789      * @param objectFactoryClass
790      *            the object factory class
791      */
792     public void setObjectFactory(Class<? extends ObjectFactory> objectFactoryClass) {
793         if (objectFactoryClass == null) {
794             remove(SessionParameter.OBJECT_FACTORY_CLASS);
795         } else {
796             put(SessionParameter.OBJECT_FACTORY_CLASS, objectFactoryClass.getName());
797         }
798     }
799 
800     // --- load and save ---
801 
802     /**
803      * Loads entries from the given UTF-8 encoded file.
804      * 
805      * @param file
806      *            the file
807      * 
808      * @throws IOException
809      *             if the entries cannot be read
810      * 
811      * @see #load(InputStream)
812      */
813     public void load(File file) throws IOException {
814         if (file == null) {
815             throw new IllegalArgumentException("File must be set!");
816         }
817 
818         FileInputStream stream = new FileInputStream(file);
819         try {
820             load(stream);
821         } finally {
822             try {
823                 stream.close();
824             } finally {
825                 // ignore
826             }
827         }
828     }
829 
830     /**
831      * Loads entries from the given, UTF-8 encoded stream and leaves the stream
832      * open. Empty lines and lines starting with '#' are ignored. Entries are
833      * added and replaced.
834      * 
835      * @param stream
836      *            the stream
837      * 
838      * @throws IOException
839      *             if the entries cannot be read
840      */
841     public void load(InputStream stream) throws IOException {
842         if (stream == null) {
843             throw new IllegalArgumentException("Stream must be set!");
844         }
845 
846         BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF8"));
847 
848         String line;
849         while ((line = reader.readLine()) != null) {
850             putLine(line);
851         }
852     }
853 
854     /**
855      * Parses a string that contains key-value pairs.
856      * 
857      * @param parameters
858      *            the parameters string
859      */
860     public void parse(String parameters) {
861         if (parameters == null) {
862             throw new IllegalArgumentException("Parameters string must be set!");
863         }
864 
865         for (String line : parameters.split("\n")) {
866             putLine(line);
867         }
868     }
869 
870     protected void putLine(String line) {
871         assert line != null;
872 
873         String lineTrim = line.trim();
874         if (lineTrim.length() == 0 || lineTrim.charAt(0) == '#') {
875             return;
876         }
877 
878         int sep = lineTrim.indexOf('=');
879         if (sep == -1) {
880             sep = lineTrim.indexOf(':');
881         }
882 
883         if (sep == -1) {
884             put(lineTrim, null);
885         } else {
886             put(lineTrim.substring(0, sep).trim(), lineTrim.substring(sep + 1).trim());
887         }
888     }
889 
890     /**
891      * Writes all entries to the given file.
892      * 
893      * @param file
894      *            the file
895      * 
896      * @throws IOException
897      *             if the entries cannot be written
898      * 
899      * @see #store(OutputStream)
900      */
901     public final void store(File file) throws IOException {
902         if (file == null) {
903             throw new IllegalArgumentException("File must be set!");
904         }
905 
906         FileOutputStream stream = new FileOutputStream(file);
907         try {
908             store(stream);
909         } finally {
910             try {
911                 stream.close();
912             } finally {
913                 // ignore
914             }
915         }
916     }
917 
918     /**
919      * Writes all entries UTF-8 encoded to the given stream and leaves the
920      * stream open.
921      * 
922      * @param stream
923      *            the stream
924      * 
925      * @throws IOException
926      *             if the entries cannot be written
927      */
928     public void store(final OutputStream stream) throws IOException {
929         if (stream == null) {
930             throw new IllegalArgumentException("Stream must be set!");
931         }
932 
933         BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stream, "UTF-8"));
934 
935         List<String> keys = new ArrayList<String>(keySet());
936         Collections.sort(keys);
937 
938         for (String key : keys) {
939             String value = get(key);
940             if (value == null) {
941                 value = "";
942             }
943 
944             writer.write(key);
945             writer.write('=');
946             writer.write(value);
947             writer.newLine();
948         }
949 
950         writer.flush();
951     }
952 
953     @Override
954     public String toString() {
955         StringBuilder sb = new StringBuilder(128);
956 
957         for (Map.Entry<String, String> entry : entrySet()) {
958             sb.append(entry.getKey());
959             sb.append('=');
960             sb.append(entry.getValue());
961             sb.append('\n');
962         }
963 
964         return sb.toString();
965     }
966 
967 }